From bd36f9eba8c007e90ee9f1f93fce204fd7eaeb6d Mon Sep 17 00:00:00 2001 From: Alexey Efimov Date: Wed, 29 May 2024 22:16:24 +0700 Subject: [PATCH] cleanup api and add local pdisk restart handler (#4982) --- ydb/core/mon/async_http_mon.cpp | 1 + ydb/core/viewer/json_acl.h | 8 +- ydb/core/viewer/json_autocomplete.h | 2 +- ydb/core/viewer/json_browse.h | 2 +- ydb/core/viewer/json_bscontrollerinfo.h | 2 +- ydb/core/viewer/json_config.h | 2 +- ydb/core/viewer/json_counters.h | 2 +- ydb/core/viewer/json_describe.h | 7 +- ydb/core/viewer/json_graph.h | 8 +- ydb/core/viewer/json_handlers.h | 14 +- ydb/core/viewer/json_handlers_pdisk.cpp | 15 ++ ydb/core/viewer/json_handlers_vdisk.cpp | 6 +- ydb/core/viewer/json_handlers_viewer.cpp | 76 ++++---- ydb/core/viewer/json_healthcheck.h | 2 +- ydb/core/viewer/json_hiveinfo.h | 2 +- ydb/core/viewer/json_hivestats.h | 2 +- ydb/core/viewer/json_hotkeys.h | 8 +- ydb/core/viewer/json_labeledcounters.h | 2 +- ydb/core/viewer/json_local_rpc.h | 10 +- ydb/core/viewer/json_metainfo.h | 2 +- ydb/core/viewer/json_netinfo.h | 2 +- ydb/core/viewer/json_nodelist.h | 2 +- ydb/core/viewer/json_pdisk_restart.h | 232 +++++++++++++++++++++++ ydb/core/viewer/json_pipe_req.h | 1 + ydb/core/viewer/json_pqconsumerinfo.h | 2 +- ydb/core/viewer/json_query.h | 6 +- ydb/core/viewer/json_render.h | 8 +- ydb/core/viewer/json_tabletcounters.h | 2 +- ydb/core/viewer/json_tenantinfo.h | 2 +- ydb/core/viewer/json_tenants.h | 2 +- ydb/core/viewer/json_topicinfo.h | 2 +- ydb/core/viewer/viewer.cpp | 173 +++++++++++------ ydb/core/viewer/viewer.h | 9 +- ydb/core/viewer/ya.make | 1 + ydb/library/actors/http/http_static.cpp | 2 +- 35 files changed, 471 insertions(+), 148 deletions(-) create mode 100644 ydb/core/viewer/json_handlers_pdisk.cpp create mode 100644 ydb/core/viewer/json_pdisk_restart.h diff --git a/ydb/core/mon/async_http_mon.cpp b/ydb/core/mon/async_http_mon.cpp index c7b3ba721582..d2c571ae9f4a 100644 --- a/ydb/core/mon/async_http_mon.cpp +++ b/ydb/core/mon/async_http_mon.cpp @@ -732,6 +732,7 @@ void TAsyncHttpMon::Start(TActorSystem* actorSystem) { "text/javascript", "application/javascript", "application/json", + "application/yaml", }; addPort->SslCertificatePem = Config.Certificate; addPort->Secure = !Config.Certificate.empty(); diff --git a/ydb/core/viewer/json_acl.h b/ydb/core/viewer/json_acl.h index 740d34776440..76c542b2032d 100644 --- a/ydb/core/viewer/json_acl.h +++ b/ydb/core/viewer/json_acl.h @@ -80,7 +80,6 @@ class TJsonACL : public TViewerPipeClient { void ReplyAndPassAway() { TStringStream json; - TString headers = Viewer->GetHTTPOKJSON(Event->Get()); if (DescribeResult != nullptr) { //TProtoToJson::ProtoToJson(json, DescribeResult->GetRecord(), JsonSettings); const auto& pbRecord(DescribeResult->GetRecord()); @@ -155,8 +154,9 @@ class TJsonACL : public TViewerPipeClient { switch (DescribeResult->GetRecord().GetStatus()) { case NKikimrScheme::StatusAccessDenied: - headers = Viewer->GetHTTPFORBIDDEN(Event->Get()); - break; + Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPFORBIDDEN(Event->Get()), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); + PassAway(); + return; default: break; } @@ -164,7 +164,7 @@ class TJsonACL : public TViewerPipeClient { json << "null"; } - Send(Event->Sender, new NMon::TEvHttpInfoRes(headers + json.Str(), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); + Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get(), json.Str()), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); PassAway(); } diff --git a/ydb/core/viewer/json_autocomplete.h b/ydb/core/viewer/json_autocomplete.h index 36d5c1347f49..155a960af2ea 100644 --- a/ydb/core/viewer/json_autocomplete.h +++ b/ydb/core/viewer/json_autocomplete.h @@ -390,7 +390,7 @@ class TJsonAutocomplete : public TViewerPipeClient { } else { TStringStream json; TProtoToJson::ProtoToJson(json, Result, JsonSettings); - Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get()) + json.Str(), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); + Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get(), json.Str()), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); } } diff --git a/ydb/core/viewer/json_browse.h b/ydb/core/viewer/json_browse.h index 3726b9ac7b77..fe3fd9e9685d 100644 --- a/ydb/core/viewer/json_browse.h +++ b/ydb/core/viewer/json_browse.h @@ -178,7 +178,7 @@ class TJsonBrowse : public TActorBootstrapped { } TProtoToJson::ProtoToJson(json, browseInfo, JsonSettings); } - ctx.Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get()) + json.Str(), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); + ctx.Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get(), json.Str()), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); Die(ctx); } diff --git a/ydb/core/viewer/json_bscontrollerinfo.h b/ydb/core/viewer/json_bscontrollerinfo.h index 243d1d348271..1e0263115a5f 100644 --- a/ydb/core/viewer/json_bscontrollerinfo.h +++ b/ydb/core/viewer/json_bscontrollerinfo.h @@ -61,7 +61,7 @@ class TJsonBSControllerInfo : public TViewerPipeClient { } else { json << "null"; } - Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get()) + json.Str(), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); + Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get(), json.Str()), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); PassAway(); } diff --git a/ydb/core/viewer/json_config.h b/ydb/core/viewer/json_config.h index 7ad11bad5692..e239c82fc4f8 100644 --- a/ydb/core/viewer/json_config.h +++ b/ydb/core/viewer/json_config.h @@ -35,7 +35,7 @@ class TJsonConfig : public TActorBootstrapped { config.MutableNameserviceConfig()->ClearAcceptUUID(); config.ClearAuthConfig(); TProtoToJson::ProtoToJson(json, config); - ctx.Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get()) + json.Str(), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); + ctx.Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get(), json.Str()), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); Die(ctx); } }; diff --git a/ydb/core/viewer/json_counters.h b/ydb/core/viewer/json_counters.h index 55eea4bdca5e..8ad296bcbe43 100644 --- a/ydb/core/viewer/json_counters.h +++ b/ydb/core/viewer/json_counters.h @@ -425,7 +425,7 @@ class TJsonCounters : public TActorBootstrapped { json << ']'; json << '}'; - ctx.Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get()) + json.Str(), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); + ctx.Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get(), json.Str()), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); Die(ctx); } diff --git a/ydb/core/viewer/json_describe.h b/ydb/core/viewer/json_describe.h index bf3134d1a1ef..e3c7337a9fff 100644 --- a/ydb/core/viewer/json_describe.h +++ b/ydb/core/viewer/json_describe.h @@ -232,7 +232,6 @@ class TJsonDescribe : public TViewerPipeClient { void ReplyAndPassAway() { TStringStream json; - TString headers = Viewer->GetHTTPOKJSON(Event->Get()); if (SchemeShardResult != nullptr && SchemeShardResult->GetRecord().GetStatus() == NKikimrScheme::EStatus::StatusSuccess) { DescribeResult = GetSchemeShardDescribeSchemeInfo(); } else if (CacheResult != nullptr) { @@ -264,7 +263,9 @@ class TJsonDescribe : public TViewerPipeClient { const auto *descriptor = NKikimrScheme::EStatus_descriptor(); auto accessDeniedStatus = descriptor->FindValueByNumber(NKikimrScheme::StatusAccessDenied)->name(); if (DescribeResult->GetStatus() == accessDeniedStatus) { - headers = Viewer->GetHTTPFORBIDDEN(Event->Get()); + Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPFORBIDDEN(Event->Get()), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); + PassAway(); + return; } TProtoToJson::ProtoToJson(json, *DescribeResult, JsonSettings); DecodeExternalTableContent(json); @@ -272,7 +273,7 @@ class TJsonDescribe : public TViewerPipeClient { json << "null"; } - Send(Event->Sender, new NMon::TEvHttpInfoRes(headers + json.Str(), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); + Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get(), json.Str()), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); PassAway(); } diff --git a/ydb/core/viewer/json_graph.h b/ydb/core/viewer/json_graph.h index 5e4812b4e0e0..20fa68980227 100644 --- a/ydb/core/viewer/json_graph.h +++ b/ydb/core/viewer/json_graph.h @@ -69,13 +69,13 @@ class TJsonGraph : public TActorBootstrapped { if (response.GetError()) { json["status"] = "error"; json["error"] = response.GetError(); - Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get()) + NJson::WriteJson(json, false), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); + Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get(), NJson::WriteJson(json, false)), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); return PassAway(); } if (response.DataSize() != Metrics.size()) { json["status"] = "error"; json["error"] = "Invalid data size received"; - Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get()) + NJson::WriteJson(json, false), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); + Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get(), NJson::WriteJson(json, false)), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); return PassAway(); } for (size_t nMetric = 0; nMetric < response.DataSize(); ++nMetric) { @@ -83,7 +83,7 @@ class TJsonGraph : public TActorBootstrapped { if (response.TimeSize() != protoMetric.ValuesSize()) { json["status"] = "error"; json["error"] = "Invalid value size received"; - Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get()) + NJson::WriteJson(json, false), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); + Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get(), NJson::WriteJson(json, false)), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); return PassAway(); } } @@ -133,7 +133,7 @@ class TJsonGraph : public TActorBootstrapped { } } - Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get()) + NJson::WriteJson(json, false), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); + Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get(), NJson::WriteJson(json, false)), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); PassAway(); } diff --git a/ydb/core/viewer/json_handlers.h b/ydb/core/viewer/json_handlers.h index fac0f35a6fac..bfe329ad9385 100644 --- a/ydb/core/viewer/json_handlers.h +++ b/ydb/core/viewer/json_handlers.h @@ -13,6 +13,7 @@ class TJsonHandlerBase { virtual TString GetRequestSummary() = 0; virtual TString GetRequestDescription() = 0; virtual YAML::Node GetRequestParameters() = 0; + virtual YAML::Node GetRequestSwagger() = 0; }; template @@ -41,15 +42,20 @@ class TJsonHandler : public TJsonHandlerBase { static YAML::Node parameters = TJsonRequestParameters::GetParameters(); return parameters; } + + YAML::Node GetRequestSwagger() override { + static YAML::Node swagger = TJsonRequestSwagger::GetSwagger(); + return swagger; + } }; struct TJsonHandlers { std::vector JsonHandlersList; - THashMap> JsonHandlersIndex; + THashMap> JsonHandlersIndex; - void AddHandler(const TString& name, TAutoPtr handler) { + void AddHandler(const TString& name, TJsonHandlerBase* handler) { JsonHandlersList.push_back(name); - JsonHandlersIndex[name] = std::move(handler); + JsonHandlersIndex[name] = std::shared_ptr(handler); } TJsonHandlerBase* FindHandler(const TString& name) const { @@ -57,7 +63,7 @@ struct TJsonHandlers { if (it == JsonHandlersIndex.end()) { return nullptr; } - return it->second.Get(); + return it->second.get(); } }; diff --git a/ydb/core/viewer/json_handlers_pdisk.cpp b/ydb/core/viewer/json_handlers_pdisk.cpp new file mode 100644 index 000000000000..4841e378dbac --- /dev/null +++ b/ydb/core/viewer/json_handlers_pdisk.cpp @@ -0,0 +1,15 @@ +#include +#include + +#include "json_handlers.h" + +#include "json_pdisk_restart.h" + + +namespace NKikimr::NViewer { + +void InitPDiskJsonHandlers(TJsonHandlers& jsonHandlers) { + jsonHandlers.AddHandler("/pdisk/restart", new TJsonHandler); +} + +} diff --git a/ydb/core/viewer/json_handlers_vdisk.cpp b/ydb/core/viewer/json_handlers_vdisk.cpp index e137b89228bc..1e243d0331a1 100644 --- a/ydb/core/viewer/json_handlers_vdisk.cpp +++ b/ydb/core/viewer/json_handlers_vdisk.cpp @@ -11,9 +11,9 @@ namespace NKikimr::NViewer { void InitVDiskJsonHandlers(TJsonHandlers& jsonHandlers) { - jsonHandlers.AddHandler("/vdisk/json/vdiskstat", new TJsonHandler); - jsonHandlers.AddHandler("/vdisk/json/getblob", new TJsonHandler); - jsonHandlers.AddHandler("/vdisk/json/blobindexstat", new TJsonHandler); + jsonHandlers.AddHandler("/vdisk/vdiskstat", new TJsonHandler); + jsonHandlers.AddHandler("/vdisk/getblob", new TJsonHandler); + jsonHandlers.AddHandler("/vdisk/blobindexstat", new TJsonHandler); } } diff --git a/ydb/core/viewer/json_handlers_viewer.cpp b/ydb/core/viewer/json_handlers_viewer.cpp index ebd93602bdc3..0f77e0008e76 100644 --- a/ydb/core/viewer/json_handlers_viewer.cpp +++ b/ydb/core/viewer/json_handlers_viewer.cpp @@ -43,44 +43,44 @@ namespace NKikimr::NViewer { void InitViewerJsonHandlers(TJsonHandlers& jsonHandlers) { - jsonHandlers.AddHandler("/viewer/json/nodelist", new TJsonHandler); - jsonHandlers.AddHandler("/viewer/json/nodeinfo", new TJsonHandler); - jsonHandlers.AddHandler("/viewer/json/sysinfo", new TJsonHandler); - jsonHandlers.AddHandler("/viewer/json/vdiskinfo", new TJsonHandler); - jsonHandlers.AddHandler("/viewer/json/pdiskinfo", new TJsonHandler); - jsonHandlers.AddHandler("/viewer/json/tabletinfo", new TJsonHandler); - jsonHandlers.AddHandler("/viewer/json/describe", new TJsonHandler); - jsonHandlers.AddHandler("/viewer/json/describe_topic", new TJsonHandler); - jsonHandlers.AddHandler("/viewer/json/describe_consumer", new TJsonHandler); - jsonHandlers.AddHandler("/viewer/json/hotkeys", new TJsonHandler); - jsonHandlers.AddHandler("/viewer/json/hiveinfo", new TJsonHandler); - jsonHandlers.AddHandler("/viewer/json/bsgroupinfo", new TJsonHandler); - jsonHandlers.AddHandler("/viewer/json/bscontrollerinfo", new TJsonHandler); - jsonHandlers.AddHandler("/viewer/json/config", new TJsonHandler); - jsonHandlers.AddHandler("/viewer/json/counters", new TJsonHandler); - jsonHandlers.AddHandler("/viewer/json/topicinfo", new TJsonHandler); - jsonHandlers.AddHandler("/viewer/json/pqconsumerinfo", new TJsonHandler); - jsonHandlers.AddHandler("/viewer/json/tabletcounters", new TJsonHandler); - jsonHandlers.AddHandler("/viewer/json/storage", new TJsonHandler); - jsonHandlers.AddHandler("/viewer/json/storage_usage", new TJsonHandler); - jsonHandlers.AddHandler("/viewer/json/metainfo", new TJsonHandler); - jsonHandlers.AddHandler("/viewer/json/browse", new TJsonHandler); - jsonHandlers.AddHandler("/viewer/json/cluster", new TJsonHandler); - jsonHandlers.AddHandler("/viewer/json/content", new TJsonHandler); - jsonHandlers.AddHandler("/viewer/json/labeledcounters", new TJsonHandler); - jsonHandlers.AddHandler("/viewer/json/tenants", new TJsonHandler); - jsonHandlers.AddHandler("/viewer/json/hivestats", new TJsonHandler); - jsonHandlers.AddHandler("/viewer/json/tenantinfo", new TJsonHandler); - jsonHandlers.AddHandler("/viewer/json/whoami", new TJsonHandler); - jsonHandlers.AddHandler("/viewer/json/query", new TJsonHandler); - jsonHandlers.AddHandler("/viewer/json/netinfo", new TJsonHandler); - jsonHandlers.AddHandler("/viewer/json/compute", new TJsonHandler); - jsonHandlers.AddHandler("/viewer/json/healthcheck", new TJsonHandler); - jsonHandlers.AddHandler("/viewer/json/nodes", new TJsonHandler); - jsonHandlers.AddHandler("/viewer/json/acl", new TJsonHandler); - jsonHandlers.AddHandler("/viewer/json/graph", new TJsonHandler); - jsonHandlers.AddHandler("/viewer/json/render", new TJsonHandler); - jsonHandlers.AddHandler("/viewer/json/autocomplete", new TJsonHandler); + jsonHandlers.AddHandler("/viewer/nodelist", new TJsonHandler); + jsonHandlers.AddHandler("/viewer/nodeinfo", new TJsonHandler); + jsonHandlers.AddHandler("/viewer/sysinfo", new TJsonHandler); + jsonHandlers.AddHandler("/viewer/vdiskinfo", new TJsonHandler); + jsonHandlers.AddHandler("/viewer/pdiskinfo", new TJsonHandler); + jsonHandlers.AddHandler("/viewer/tabletinfo", new TJsonHandler); + jsonHandlers.AddHandler("/viewer/describe", new TJsonHandler); + jsonHandlers.AddHandler("/viewer/describe_topic", new TJsonHandler); + jsonHandlers.AddHandler("/viewer/describe_consumer", new TJsonHandler); + jsonHandlers.AddHandler("/viewer/hotkeys", new TJsonHandler); + jsonHandlers.AddHandler("/viewer/hiveinfo", new TJsonHandler); + jsonHandlers.AddHandler("/viewer/bsgroupinfo", new TJsonHandler); + jsonHandlers.AddHandler("/viewer/bscontrollerinfo", new TJsonHandler); + jsonHandlers.AddHandler("/viewer/config", new TJsonHandler); + jsonHandlers.AddHandler("/viewer/counters", new TJsonHandler); + jsonHandlers.AddHandler("/viewer/topicinfo", new TJsonHandler); + jsonHandlers.AddHandler("/viewer/pqconsumerinfo", new TJsonHandler); + jsonHandlers.AddHandler("/viewer/tabletcounters", new TJsonHandler); + jsonHandlers.AddHandler("/viewer/storage", new TJsonHandler); + jsonHandlers.AddHandler("/viewer/storage_usage", new TJsonHandler); + jsonHandlers.AddHandler("/viewer/metainfo", new TJsonHandler); + jsonHandlers.AddHandler("/viewer/browse", new TJsonHandler); + jsonHandlers.AddHandler("/viewer/cluster", new TJsonHandler); + jsonHandlers.AddHandler("/viewer/content", new TJsonHandler); + jsonHandlers.AddHandler("/viewer/labeledcounters", new TJsonHandler); + jsonHandlers.AddHandler("/viewer/tenants", new TJsonHandler); + jsonHandlers.AddHandler("/viewer/hivestats", new TJsonHandler); + jsonHandlers.AddHandler("/viewer/tenantinfo", new TJsonHandler); + jsonHandlers.AddHandler("/viewer/whoami", new TJsonHandler); + jsonHandlers.AddHandler("/viewer/query", new TJsonHandler); + jsonHandlers.AddHandler("/viewer/netinfo", new TJsonHandler); + jsonHandlers.AddHandler("/viewer/compute", new TJsonHandler); + jsonHandlers.AddHandler("/viewer/healthcheck", new TJsonHandler); + jsonHandlers.AddHandler("/viewer/nodes", new TJsonHandler); + jsonHandlers.AddHandler("/viewer/acl", new TJsonHandler); + jsonHandlers.AddHandler("/viewer/graph", new TJsonHandler); + jsonHandlers.AddHandler("/viewer/render", new TJsonHandler); + jsonHandlers.AddHandler("/viewer/autocomplete", new TJsonHandler); } } diff --git a/ydb/core/viewer/json_healthcheck.h b/ydb/core/viewer/json_healthcheck.h index d2abcf08f7d6..256a9da018a3 100644 --- a/ydb/core/viewer/json_healthcheck.h +++ b/ydb/core/viewer/json_healthcheck.h @@ -126,7 +126,7 @@ class TJsonHealthCheck : public TActorBootstrapped { void HandleJSON(NHealthCheck::TEvSelfCheckResult::TPtr& ev, const TActorContext &ctx) { TStringStream json; TProtoToJson::ProtoToJson(json, ev->Get()->Result, JsonSettings); - ctx.Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get()) + json.Str(), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); + ctx.Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get(), json.Str()), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); Die(ctx); } diff --git a/ydb/core/viewer/json_hiveinfo.h b/ydb/core/viewer/json_hiveinfo.h index 03a848dc5f9d..d5f97f8eabe0 100644 --- a/ydb/core/viewer/json_hiveinfo.h +++ b/ydb/core/viewer/json_hiveinfo.h @@ -91,7 +91,7 @@ class TJsonHiveInfo : public TViewerPipeClient { } else { json << "null"; } - Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get()) + json.Str(), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); + Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get(), json.Str()), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); PassAway(); } diff --git a/ydb/core/viewer/json_hivestats.h b/ydb/core/viewer/json_hivestats.h index 3b5afe189ac1..483c0e5c120a 100644 --- a/ydb/core/viewer/json_hivestats.h +++ b/ydb/core/viewer/json_hivestats.h @@ -69,7 +69,7 @@ class TJsonHiveStats : public TViewerPipeClient { } else { json << "null"; } - Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get()) + json.Str(), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); + Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get(), json.Str()), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); PassAway(); } diff --git a/ydb/core/viewer/json_hotkeys.h b/ydb/core/viewer/json_hotkeys.h index f90a40747bef..b4922a4af965 100644 --- a/ydb/core/viewer/json_hotkeys.h +++ b/ydb/core/viewer/json_hotkeys.h @@ -142,12 +142,12 @@ class TJsonHotkeys : public TViewerPipeClient { } void ReplyAndPassAway() { - TString headers = Viewer->GetHTTPOKJSON(Event->Get()); if (DescribeResult != nullptr) { switch (DescribeResult->GetRecord().GetStatus()) { case NKikimrScheme::StatusAccessDenied: - headers = Viewer->GetHTTPFORBIDDEN(Event->Get()); - break; + Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPFORBIDDEN(Event->Get()), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); + PassAway(); + return; default: break; } @@ -155,7 +155,7 @@ class TJsonHotkeys : public TViewerPipeClient { NJson::TJsonValue root = BuildResponse(); TString json = NJson::WriteJson(root, false); - Send(Event->Sender, new NMon::TEvHttpInfoRes(headers + json, 0, NMon::IEvHttpInfoRes::EContentType::Custom)); + Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get(), json), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); PassAway(); } diff --git a/ydb/core/viewer/json_labeledcounters.h b/ydb/core/viewer/json_labeledcounters.h index 4a3305d20223..c8ea014b6205 100644 --- a/ydb/core/viewer/json_labeledcounters.h +++ b/ydb/core/viewer/json_labeledcounters.h @@ -137,7 +137,7 @@ class TJsonLabeledCounters : public TActorBootstrapped { void ReplyAndDie(const TActorContext &ctx) { TStringStream json; TProtoToJson::ProtoToJson(json, LabeledCountersResult, JsonSettings); - ctx.Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get()) + json.Str(), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); + ctx.Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get(), json.Str()), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); Die(ctx); } diff --git a/ydb/core/viewer/json_local_rpc.h b/ydb/core/viewer/json_local_rpc.h index e7d1fd6ebdde..45fd823ce56c 100644 --- a/ydb/core/viewer/json_local_rpc.h +++ b/ydb/core/viewer/json_local_rpc.h @@ -192,13 +192,15 @@ class TJsonLocalRpc : public TActorBootstrappedGetHTTPOKJSON(Event->Get()); if (DescribeResult) { if (!DescribeResult->Status->IsSuccess()) { - headers = Viewer->GetHTTPBADREQUEST(Event->Get(), {}, "Bad Request"); if (DescribeResult->Status->GetStatus() == NYdb::EStatus::UNAUTHORIZED) { - headers = Viewer->GetHTTPFORBIDDEN(Event->Get()); + Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPFORBIDDEN(Event->Get()), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); + } else { + Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPBADREQUEST(Event->Get()), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); } + PassAway(); + return; } else { TProtoToJson::ProtoToJson(json, *(DescribeResult->Message), JsonSettings); } @@ -206,7 +208,7 @@ class TJsonLocalRpc : public TActorBootstrappedSender, new NMon::TEvHttpInfoRes(headers + json.Str(), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); + Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get(), json.Str()), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); PassAway(); } diff --git a/ydb/core/viewer/json_metainfo.h b/ydb/core/viewer/json_metainfo.h index 42fb72174df7..3f5e51f9d129 100644 --- a/ydb/core/viewer/json_metainfo.h +++ b/ydb/core/viewer/json_metainfo.h @@ -108,7 +108,7 @@ class TJsonMetaInfo : public TActorBootstrapped { void ReplyAndDie(const TActorContext &ctx) { TStringStream json; TProtoToJson::ProtoToJson(json, MetaInfo, JsonSettings); - ctx.Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get()) + json.Str(), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); + ctx.Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get(), json.Str()), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); Die(ctx); } diff --git a/ydb/core/viewer/json_netinfo.h b/ydb/core/viewer/json_netinfo.h index 8e5ebe053c17..e57e18677801 100644 --- a/ydb/core/viewer/json_netinfo.h +++ b/ydb/core/viewer/json_netinfo.h @@ -289,7 +289,7 @@ class TJsonNetInfo : public TViewerPipeClient { result.SetOverall(NKikimrViewer::EFlag::Green); TStringStream json; TProtoToJson::ProtoToJson(json, result, JsonSettings); - Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get()) + json.Str(), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); + Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get(), json.Str()), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); PassAway(); } diff --git a/ydb/core/viewer/json_nodelist.h b/ydb/core/viewer/json_nodelist.h index 7017a491fe9c..77a14fe3d035 100644 --- a/ydb/core/viewer/json_nodelist.h +++ b/ydb/core/viewer/json_nodelist.h @@ -74,7 +74,7 @@ class TJsonNodeList : public TActorBootstrapped { } } } - ctx.Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get()) + NJson::WriteJson(json, false), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); + ctx.Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get(), NJson::WriteJson(json, false)), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); Die(ctx); } diff --git a/ydb/core/viewer/json_pdisk_restart.h b/ydb/core/viewer/json_pdisk_restart.h new file mode 100644 index 000000000000..49e6e373ef2d --- /dev/null +++ b/ydb/core/viewer/json_pdisk_restart.h @@ -0,0 +1,232 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include "viewer.h" +#include "json_pipe_req.h" + +namespace NKikimr { +namespace NViewer { + +using namespace NActors; + +class TJsonPDiskRestart : public TViewerPipeClient { + enum EEv { + EvRetryNodeRequest = EventSpaceBegin(NActors::TEvents::ES_PRIVATE), + EvEnd + }; + + static_assert(EvEnd < EventSpaceEnd(NActors::TEvents::ES_PRIVATE), "expect EvEnd < EventSpaceEnd(TEvents::ES_PRIVATE)"); + + struct TEvRetryNodeRequest : NActors::TEventLocal { + TEvRetryNodeRequest() + {} + }; + +protected: + using TThis = TJsonPDiskRestart; + using TBase = TViewerPipeClient; + IViewer* Viewer; + NMon::TEvHttpInfo::TPtr Event; + TJsonSettings JsonSettings; + bool AllEnums = false; + ui32 Timeout = 0; + ui32 ActualRetries = 0; + ui32 Retries = 0; + TDuration RetryPeriod = TDuration::MilliSeconds(500); + + std::unique_ptr Response; + + ui32 NodeId = 0; + ui32 PDiskId = 0; + + TActorId SessionId; + +public: + static constexpr NKikimrServices::TActivity::EType ActorActivityType() { + return NKikimrServices::TActivity::VIEWER_HANDLER; + } + + TJsonPDiskRestart(IViewer* viewer, NMon::TEvHttpInfo::TPtr& ev) + : Viewer(viewer) + , Event(ev) + {} + + void Bootstrap() { + const auto& params(Event->Get()->Request.GetParams()); + NodeId = FromStringWithDefault(params.Get("node_id"), 0); + PDiskId = FromStringWithDefault(params.Get("pdisk_id"), Max()); + + if (PDiskId == Max()) { + TBase::Send(Event->Sender, new NMon::TEvHttpInfoRes( + Viewer->GetHTTPBADREQUEST(Event->Get(), "text/plain", "field 'pdisk_id' is required"), + 0, NMon::IEvHttpInfoRes::EContentType::Custom)); + return PassAway(); + } + if (Event->Get()->Request.GetMethod() != HTTP_METHOD_POST) { + TBase::Send(Event->Sender, new NMon::TEvHttpInfoRes( + Viewer->GetHTTPBADREQUEST(Event->Get(), "text/plain", "Only POST method is allowed"), + 0, NMon::IEvHttpInfoRes::EContentType::Custom)); + return PassAway(); + } + + if (!NodeId) { + NodeId = TlsActivationContext->ActorSystem()->NodeId; + } + TBase::InitConfig(params); + + Timeout = FromStringWithDefault(params.Get("timeout"), 10000); + Retries = FromStringWithDefault(params.Get("retries"), 0); + RetryPeriod = TDuration::MilliSeconds(FromStringWithDefault(params.Get("retry_period"), RetryPeriod.MilliSeconds())); + + SendRequest(); + + TBase::Become(&TThis::StateWork, TDuration::MilliSeconds(Timeout), new TEvents::TEvWakeup()); + } + + STATEFN(StateWork) { + switch (ev->GetTypeRewrite()) { + hFunc(TEvBlobStorage::TEvAskWardenRestartPDiskResult, Handle); + cFunc(TEvRetryNodeRequest::EventType, HandleRetry); + cFunc(TEvents::TEvUndelivered::EventType, Undelivered); + hFunc(TEvInterconnect::TEvNodeConnected, Connected); + hFunc(TEvInterconnect::TEvNodeDisconnected, Disconnected); + cFunc(TEvents::TSystem::Wakeup, HandleTimeout); + } + } + + void SendRequest() { + auto request = MakeHolder(PDiskId); + TBase::SendRequest(MakeBlobStorageNodeWardenID(NodeId), + request.Release(), + IEventHandle::FlagTrackDelivery | IEventHandle::FlagSubscribeOnSession, + NodeId); + } + + bool RetryRequest() { + if (Retries) { + if (++ActualRetries <= Retries) { + TBase::Schedule(RetryPeriod, new TEvRetryNodeRequest()); + return true; + } + } + return false; + } + + void Undelivered() { + if (!RetryRequest()) { + TBase::RequestDone(); + } + } + + void Connected(TEvInterconnect::TEvNodeConnected::TPtr& ev) { + SessionId = ev->Sender; + } + + void Disconnected(TEvInterconnect::TEvNodeDisconnected::TPtr&) { + SessionId = {}; + if (!RetryRequest()) { + TBase::RequestDone(); + } + } + + void Handle(TEvBlobStorage::TEvAskWardenRestartPDiskResult::TPtr& ev) { + Response.reset(ev->Release().Release()); + ReplyAndPassAway(); + } + + void HandleRetry() { + SendRequest(); + } + + void HandleTimeout() { + Send(Event->Sender, new NMon::TEvHttpInfoRes( + Viewer->GetHTTPGATEWAYTIMEOUT(Event->Get(), "text/plain", "Timeout receiving response from NodeWarden"), + 0, NMon::IEvHttpInfoRes::EContentType::Custom)); + } + + void PassAway() override { + if (SessionId) { + TBase::Send(SessionId, new TEvents::TEvUnsubscribe()); + } + TBase::PassAway(); + } + + void ReplyAndPassAway() { + NJson::TJsonValue json; + if (Response != nullptr) { + json["result"] = Response->RestartAllowed; + if (Response->Details) { + json["error"] = Response->Details; + } + } else { + json["result"] = false; + json["error"] = "No response was received from the NodeWarden"; + } + TBase::Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get(), NJson::WriteJson(json)), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); + PassAway(); + } +}; + +template <> +YAML::Node TJsonRequestSwagger::GetSwagger() { + return YAML::Load(R"___( + post: + tags: + - pdisk + produces: + - application/json + summary: Restart PDisk + description: Restart PDisk on the specified node + parameters: + - name: node_id + in: query + description: node identifier + type: integer + - name: pdisk_id + in: query + description: pdisk identifier + required: true + type: integer + - name: timeout + in: query + description: timeout in ms + required: false + type: integer + - name: retries + in: query + description: number of retries + required: false + type: integer + - name: retry_period + in: query + description: retry period in ms + required: false + type: integer + default: 500 + responses: + 200: + description: OK + schema: + type: object + properties: + result: + type: boolean + description: was operation successful or not + error: + type: string + description: details about failed operation + 400: + description: Bad Request + 403: + description: Forbidden + 504: + description: Gateway Timeout + )___"); +} + +} +} diff --git a/ydb/core/viewer/json_pipe_req.h b/ydb/core/viewer/json_pipe_req.h index 2f8574a4322c..2022692f9101 100644 --- a/ydb/core/viewer/json_pipe_req.h +++ b/ydb/core/viewer/json_pipe_req.h @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include diff --git a/ydb/core/viewer/json_pqconsumerinfo.h b/ydb/core/viewer/json_pqconsumerinfo.h index b88e1614963a..0071ec99e8bd 100644 --- a/ydb/core/viewer/json_pqconsumerinfo.h +++ b/ydb/core/viewer/json_pqconsumerinfo.h @@ -107,7 +107,7 @@ class TJsonPQConsumerInfo : public TActorBootstrapped { void ReplyAndDie(const TActorContext &ctx) { TStringStream json; TProtoToJson::ProtoToJson(json, Result.GetMetaResponse(), JsonSettings); - ctx.Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get()) + json.Str(), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); + ctx.Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get(), json.Str()), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); Die(ctx); } diff --git a/ydb/core/viewer/json_query.h b/ydb/core/viewer/json_query.h index 1b034072f926..60ba1e15106a 100644 --- a/ydb/core/viewer/json_query.h +++ b/ydb/core/viewer/json_query.h @@ -449,7 +449,8 @@ class TJsonQuery : public TViewerPipeClient { void HandleTimeout() { if (Event) { - ReplyAndPassAway(Viewer->GetHTTPGATEWAYTIMEOUT(Event->Get())); + Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPGATEWAYTIMEOUT(Event->Get()), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); + PassAway(); } else { auto* response = new TEvViewer::TEvViewerResponse(); response->Record.MutableQueryResponse()->SetYdbStatus(Ydb::StatusIds::TIMEOUT); @@ -463,7 +464,7 @@ class TJsonQuery : public TViewerPipeClient { } void ReplyAndPassAway(TString data) { - Send(Event->Sender, new NMon::TEvHttpInfoRes(std::move(data), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); + Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get(), std::move(data)), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); PassAway(); } @@ -514,7 +515,6 @@ class TJsonQuery : public TViewerPipeClient { } } - out << Viewer->GetHTTPOKJSON(Event->Get()); if (ResultSets.size() > 0) { if (Schema == ESchemaType::Classic) { NJson::TJsonValue& jsonResults = jsonResponse["result"]; diff --git a/ydb/core/viewer/json_render.h b/ydb/core/viewer/json_render.h index 419c0a08e69a..a0788879a19c 100644 --- a/ydb/core/viewer/json_render.h +++ b/ydb/core/viewer/json_render.h @@ -200,13 +200,13 @@ class TJsonRender : public TViewerPipeClient { if (response.GetError()) { json["status"] = "error"; json["error"] = response.GetError(); - ReplyAndPassAway(Viewer->GetHTTPOKJSON(Event->Get()) + NJson::WriteJson(json, false)); + ReplyAndPassAway(Viewer->GetHTTPOKJSON(Event->Get(), NJson::WriteJson(json, false))); return; } if (response.DataSize() != Metrics.size()) { json["status"] = "error"; json["error"] = "Invalid data size received"; - ReplyAndPassAway(Viewer->GetHTTPOKJSON(Event->Get()) + NJson::WriteJson(json, false)); + ReplyAndPassAway(Viewer->GetHTTPOKJSON(Event->Get(), NJson::WriteJson(json, false))); return; } for (size_t nMetric = 0; nMetric < response.DataSize(); ++nMetric) { @@ -214,7 +214,7 @@ class TJsonRender : public TViewerPipeClient { if (response.TimeSize() != protoMetric.ValuesSize()) { json["status"] = "error"; json["error"] = "Invalid value size received"; - ReplyAndPassAway(Viewer->GetHTTPOKJSON(Event->Get()) + NJson::WriteJson(json, false)); + ReplyAndPassAway(Viewer->GetHTTPOKJSON(Event->Get(), NJson::WriteJson(json, false))); return; } } @@ -241,7 +241,7 @@ class TJsonRender : public TViewerPipeClient { } } - ReplyAndPassAway(Viewer->GetHTTPOKJSON(Event->Get()) + NJson::WriteJson(json, false)); + ReplyAndPassAway(Viewer->GetHTTPOKJSON(Event->Get(), NJson::WriteJson(json, false))); } else { TEvViewer::TEvViewerResponse* viewerResponse = new TEvViewer::TEvViewerResponse(); viewerResponse->Record.MutableRenderResponse()->CopyFrom(response); diff --git a/ydb/core/viewer/json_tabletcounters.h b/ydb/core/viewer/json_tabletcounters.h index 748fe44993ea..023552fdea3f 100644 --- a/ydb/core/viewer/json_tabletcounters.h +++ b/ydb/core/viewer/json_tabletcounters.h @@ -157,7 +157,7 @@ class TJsonTabletCounters : public TActorBootstrapped { } else { json << "null"; } - ctx.Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get()) + json.Str(), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); + ctx.Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get(), json.Str()), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); Die(ctx); } diff --git a/ydb/core/viewer/json_tenantinfo.h b/ydb/core/viewer/json_tenantinfo.h index 45a0ca62f280..3f40cd4fb3dd 100644 --- a/ydb/core/viewer/json_tenantinfo.h +++ b/ydb/core/viewer/json_tenantinfo.h @@ -757,7 +757,7 @@ class TJsonTenantInfo : public TViewerPipeClient { }); TStringStream json; TProtoToJson::ProtoToJson(json, Result, JsonSettings); - Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get()) + json.Str(), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); + Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get(), json.Str()), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); PassAway(); } diff --git a/ydb/core/viewer/json_tenants.h b/ydb/core/viewer/json_tenants.h index 097b0306b871..e15ebdfcc152 100644 --- a/ydb/core/viewer/json_tenants.h +++ b/ydb/core/viewer/json_tenants.h @@ -90,7 +90,7 @@ class TJsonTenants : public TViewerPipeClient { void ReplyAndPassAway() { TStringStream json; TProtoToJson::ProtoToJson(json, Result, JsonSettings); - Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get()) + json.Str(), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); + Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get(), json.Str()), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); PassAway(); } diff --git a/ydb/core/viewer/json_topicinfo.h b/ydb/core/viewer/json_topicinfo.h index b2a73b02b5c9..d5880859ff16 100644 --- a/ydb/core/viewer/json_topicinfo.h +++ b/ydb/core/viewer/json_topicinfo.h @@ -82,7 +82,7 @@ class TJsonTopicInfo : public TActorBootstrapped { void ReplyAndDie(const TActorContext &ctx) { TStringStream json; TProtoToJson::ProtoToJson(json, TopicInfoResult, JsonSettings); - ctx.Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get()) + json.Str(), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); + ctx.Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get(), json.Str()), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); Die(ctx); } diff --git a/ydb/core/viewer/viewer.cpp b/ydb/core/viewer/viewer.cpp index aae64d0adc74..febcb5302632 100644 --- a/ydb/core/viewer/viewer.cpp +++ b/ydb/core/viewer/viewer.cpp @@ -40,6 +40,7 @@ namespace NViewer { using namespace NNodeWhiteboard; extern void InitViewerJsonHandlers(TJsonHandlers& jsonHandlers); +extern void InitPDiskJsonHandlers(TJsonHandlers& jsonHandlers); extern void InitVDiskJsonHandlers(TJsonHandlers& jsonHandlers); void SetupPQVirtualHandlers(IViewer* viewer) { @@ -92,13 +93,13 @@ class TViewer : public TActorBootstrapped, public IViewer { if (mon) { NLwTraceMonPage::ProbeRegistry().AddProbesList(LWTRACE_GET_PROBES(VIEWER_PROVIDER)); TVector viewerAllowedSIDs; + TVector monitoringAllowedSIDs; { const auto& protoAllowedSIDs = KikimrRunConfig.AppConfig.GetDomainsConfig().GetSecurityConfig().GetViewerAllowedSIDs(); for (const auto& sid : protoAllowedSIDs) { viewerAllowedSIDs.emplace_back(sid); } } - TVector monitoringAllowedSIDs; { const auto& protoAllowedSIDs = KikimrRunConfig.AppConfig.GetDomainsConfig().GetSecurityConfig().GetMonitoringAllowedSIDs(); for (const auto& sid : protoAllowedSIDs) { @@ -146,6 +147,14 @@ class TViewer : public TActorBootstrapped, public IViewer { .UseAuth = true, .AllowedSIDs = monitoringAllowedSIDs, }); + mon->RegisterActorPage({ + .Title = "PDisk", + .RelPath = "pdisk", + .ActorSystem = ctx.ExecutorThread.ActorSystem, + .ActorId = ctx.SelfID, + .UseAuth = true, + .AllowedSIDs = monitoringAllowedSIDs, + }); auto whiteboardServiceId = NNodeWhiteboard::MakeNodeWhiteboardServiceId(ctx.SelfID.NodeId()); ctx.Send(whiteboardServiceId, new NNodeWhiteboard::TEvWhiteboard::TEvSystemStateAddEndpoint( "http-mon", Sprintf(":%d", KikimrRunConfig.AppConfig.GetMonitoringConfig().GetMonitoringPort()))); @@ -153,8 +162,26 @@ class TViewer : public TActorBootstrapped, public IViewer { AllowOrigin = KikimrRunConfig.AppConfig.GetMonitoringConfig().GetAllowOrigin(); InitViewerJsonHandlers(JsonHandlers); + InitPDiskJsonHandlers(JsonHandlers); InitVDiskJsonHandlers(JsonHandlers); + for (const auto& handler : JsonHandlers.JsonHandlersList) { + // temporary handling of old paths + TStringBuf newPath(handler); + TString oldPath = "/" + TString(newPath.After('/').Before('/')) + "/json/" + TString(newPath.After('/').After('/')); + JsonHandlers.JsonHandlersIndex[oldPath] = JsonHandlers.JsonHandlersIndex[newPath]; + } + + // TODO: redirect old paths + Redirect307["/viewer/v2/json/config"] = "/viewer/config"; + Redirect307["/viewer/v2/json/sysinfo"] = "/viewer/sysinfo"; + Redirect307["/viewer/v2/json/pdiskinfo"] = "/viewer/pdiskinfo"; + Redirect307["/viewer/v2/json/vdiskinfo"] = "/viewer/vdiskinfo"; + Redirect307["/viewer/v2/json/storage"] = "/viewer/storage"; + Redirect307["/viewer/v2/json/nodelist"] = "/viewer/nodelist"; + Redirect307["/viewer/v2/json/tabletinfo"] = "/viewer/tabletinfo"; + Redirect307["/viewer/v2/json/nodeinfo"] = "/viewer/nodeinfo"; + TWhiteboardInfo::InitMerger(); TWhiteboardInfo::InitMerger(); } @@ -166,9 +193,10 @@ class TViewer : public TActorBootstrapped, public IViewer { TString GetCORS(const NMon::TEvHttpInfo* request) override; TString GetHTTPOK(const NMon::TEvHttpInfo* request, TString type, TString response, TInstant lastModified) override; - TString GetHTTPGATEWAYTIMEOUT(const NMon::TEvHttpInfo* request) override; + TString GetHTTPGATEWAYTIMEOUT(const NMon::TEvHttpInfo* request, TString type, TString response) override; TString GetHTTPBADREQUEST(const NMon::TEvHttpInfo* request, TString type, TString response) override; TString GetHTTPFORBIDDEN(const NMon::TEvHttpInfo* request) override; + TString GetHTTPNOTFOUND(const NMon::TEvHttpInfo* request) override; void RegisterVirtualHandler( NKikimrViewer::EObjectType parentObjectType, @@ -200,6 +228,7 @@ class TViewer : public TActorBootstrapped, public IViewer { private: TJsonHandlers JsonHandlers; + std::unordered_map Redirect307; const TKikimrRunConfig KikimrRunConfig; std::unordered_multimap VirtualHandlersByParentType; std::unordered_map ContentHandlers; @@ -217,22 +246,27 @@ class TViewer : public TActorBootstrapped, public IViewer { YAML::Node GetSwaggerPathsYaml() { YAML::Node paths; for (const TString& name : JsonHandlers.JsonHandlersList) { - TAutoPtr& handler = JsonHandlers.JsonHandlersIndex[name]; + const auto& handler = JsonHandlers.JsonHandlersIndex[name]; TString tag = TString(TStringBuf(name.substr(1)).Before('/')); auto path = paths[name]; - auto get = path["get"]; - get["tags"].push_back(tag); - get["produces"].push_back("application/json"); - if (auto summary = handler->GetRequestSummary()) { - get["summary"] = summary; - } - if (auto description = handler->GetRequestDescription()) { - get["description"] = description; + auto swagger = handler->GetRequestSwagger(); + if (swagger.IsNull()) { + auto get = path["get"]; + get["tags"].push_back(tag); + get["produces"].push_back("application/json"); + if (auto summary = handler->GetRequestSummary()) { + get["summary"] = summary; + } + if (auto description = handler->GetRequestDescription()) { + get["description"] = description; + } + get["parameters"] = handler->GetRequestParameters(); + auto responses = get["responses"]; + auto response200 = responses["200"]; + response200["schema"] = handler->GetResponseJsonSchema(); + } else { + path = swagger; } - get["parameters"] = handler->GetRequestParameters(); - auto responses = get["responses"]; - auto response200 = responses["200"]; - response200["schema"] = handler->GetResponseJsonSchema(); } return paths; } @@ -251,14 +285,20 @@ class TViewer : public TActorBootstrapped, public IViewer { return yaml; } - static TInstant GetCompileTime() { - tm compileTime; + static time_t GetCompileTimeSeconds() { + tm compileTime = {}; strptime(__DATE__ " " __TIME__, "%B %d %Y %H:%M:%S", &compileTime); - return TInstant::Seconds(mktime(&compileTime)); + return mktime(&compileTime); + } + + static TInstant GetCompileTime() { + static TInstant instantTime(timeval{.tv_sec = GetCompileTimeSeconds(), .tv_usec = 0}); + return instantTime; } bool ReplyWithFile(NMon::TEvHttpInfo::TPtr& ev, const TString& name) { if (name == "/api/viewer.yaml") { + Cerr << "CompileTime is " << GetCompileTime() << Endl; Send(ev->Sender, new NMon::TEvHttpInfoRes(GetHTTPOKYAML(ev->Get(), Dump(GetSwaggerYaml()), GetCompileTime()), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); return true; } @@ -360,56 +400,56 @@ class TViewer : public TActorBootstrapped, public IViewer { } return; } - TString filename(msg->Request.GetPage()->Path + msg->Request.GetPathInfo()); - if (msg->Request.GetPathInfo().StartsWith("/json/")) { - TString path = "/" + msg->Request.GetPage()->Path + msg->Request.GetPathInfo(); - auto handler = JsonHandlers.FindHandler(path); - if (!handler) { - handler = JsonHandlers.FindHandler(TString(msg->Request.GetPathInfo())); + TString path("/" + msg->Request.GetPage()->Path + msg->Request.GetPathInfo()); + auto itRedirect307 = Redirect307.find(path); + if (itRedirect307 != Redirect307.end()) { + TString redirect(msg->Request.GetUri()); + redirect.erase(0, itRedirect307->first.size()); + redirect.insert(0, itRedirect307->second); + Send(ev->Sender, new NMon::TEvHttpInfoRes("HTTP/1.1 307 Temporary Redirect\r\nLocation: " + redirect + "\r\n\r\n", 0, NMon::IEvHttpInfoRes::EContentType::Custom)); + return; + } + auto handler = JsonHandlers.FindHandler(path); + if (handler) { + try { + ctx.ExecutorThread.RegisterActor(handler->CreateRequestActor(this, ev)); + return; } - if (handler) { - try { - ctx.ExecutorThread.RegisterActor(handler->CreateRequestActor(this, ev)); - return; - } - catch (const std::exception& e) { - ctx.Send(ev->Sender, new NMon::TEvHttpInfoRes(TString("HTTP/1.1 400 Bad Request\r\n\r\n") + e.what(), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); - return; - } + catch (const std::exception& e) { + ctx.Send(ev->Sender, new NMon::TEvHttpInfoRes(TString("HTTP/1.1 400 Bad Request\r\n\r\n") + e.what(), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); + return; } } - if (filename.StartsWith("counters/hosts")) { + if (path.StartsWith("counters/hosts")) { ctx.ExecutorThread.RegisterActor(new TCountersHostsList(this, ev)); return; } - if (filename.StartsWith("healthcheck")) { + if (path.StartsWith("healthcheck")) { ctx.ExecutorThread.RegisterActor(new TJsonHealthCheck(this, ev)); return; } // TODO: check path validity // TODO: cache if (msg->Request.GetPathInfo().StartsWith('/')) { - if (filename.StartsWith("viewer")) { - filename.erase(0, 6); - } else if (filename.StartsWith("vdisk")) { - filename.erase(0, 5); + if (path.StartsWith("/viewer")) { + path.erase(0, 7); } - if (IsMatchesWildcard(filename, "monitoring*/static/js/*") - || IsMatchesWildcard(filename, "monitoring*/static/css/*") - || IsMatchesWildcard(filename, "monitoring*/static/media/*") - || IsMatchesWildcard(filename, "monitoring*/static/assets/fonts/*") - || IsMatchesWildcard(filename, "monitoring*/static/favicon.png")) { - auto resPos = filename.find("/static/"); + if (IsMatchesWildcard(path, "monitoring*/static/js/*") + || IsMatchesWildcard(path, "monitoring*/static/css/*") + || IsMatchesWildcard(path, "monitoring*/static/media/*") + || IsMatchesWildcard(path, "monitoring*/static/assets/fonts/*") + || IsMatchesWildcard(path, "monitoring*/static/favicon.png")) { + auto resPos = path.find("/static/"); if (resPos != TString::npos) { - filename = "monitoring" + filename.substr(resPos); + path = "monitoring" + path.substr(resPos); } - } else if (filename.StartsWith("monitoring") && filename != "monitoring/index.html") { - filename = "monitoring/index.html"; + } else if (path.StartsWith("monitoring") && path != "monitoring/index.html") { + path = "monitoring/index.html"; } - if (filename.EndsWith('/')) { - filename += "index.html"; + if (path.EndsWith('/')) { + path += "index.html"; } - if (ReplyWithFile(ev, filename)) { + if (ReplyWithFile(ev, path)) { return; } } @@ -422,7 +462,7 @@ class TViewer : public TActorBootstrapped, public IViewer { ctx.Send(ev->Sender, new NMon::TEvHttpInfoRes("HTTP/1.1 302 Found\r\nLocation: " + SplitPath(msg->Request.GetPage()->Path).back() + "/\r\n\r\n", 0, NMon::IEvHttpInfoRes::EContentType::Custom)); return; } - ctx.Send(ev->Sender, new NMon::TEvHttpInfoRes(NMonitoring::HTTPNOTFOUND)); + Send(ev->Sender, new NMon::TEvHttpInfoRes(GetHTTPNOTFOUND(ev->Get()), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); } }; @@ -474,20 +514,29 @@ TString TViewer::GetCORS(const NMon::TEvHttpInfo* request) { return res; } -TString TViewer::GetHTTPGATEWAYTIMEOUT(const NMon::TEvHttpInfo* request) { +TString TViewer::GetHTTPGATEWAYTIMEOUT(const NMon::TEvHttpInfo* request, TString contentType, TString response) { TStringBuilder res; res << "HTTP/1.1 504 Gateway Time-out\r\n" << "Connection: Close\r\n" - << "X-Worker-Name: " << FQDNHostName() << ":" << CurrentWorkerName << "\r\n"; + << "X-Worker-Name: " << CurrentWorkerName << "\r\n"; + if (contentType) { + res << "Content-Type: " << contentType << "\r\n"; + } res << GetCORS(request); - res << "\r\nGateway Time-out\r\n"; + res << "\r\n"; + if (response) { + res << response << "\r\n"; + } else { + res << "Gateway Time-out\r\n"; + } return res; } TString TViewer::GetHTTPBADREQUEST(const NMon::TEvHttpInfo* request, TString contentType, TString response) { TStringBuilder res; res << "HTTP/1.1 400 Bad Request\r\n" - << "Connection: Close\r\n"; + << "Connection: Close\r\n" + << "X-Worker-Name: " << CurrentWorkerName << "\r\n"; if (contentType) { res << "Content-Type: " << contentType << "\r\n"; } @@ -502,7 +551,15 @@ TString TViewer::GetHTTPBADREQUEST(const NMon::TEvHttpInfo* request, TString con TString TViewer::GetHTTPFORBIDDEN(const NMon::TEvHttpInfo* request) { TStringBuilder res; res << "HTTP/1.1 403 Forbidden\r\n" - << "Content-Type: application/json; charset=utf-8\r\n" + << "Connection: Close\r\n"; + res << GetCORS(request); + res << "\r\n"; + return res; +} + +TString TViewer::GetHTTPNOTFOUND(const NMon::TEvHttpInfo* request) { + TStringBuilder res; + res << "HTTP/1.1 404 Not Found\r\n" << "Connection: Close\r\n"; res << GetCORS(request); res << "\r\n"; @@ -517,7 +574,7 @@ TString TViewer::GetHTTPOK(const NMon::TEvHttpInfo* request, TString contentType if (response) { res << "Content-Type: " << contentType << "\r\n"; res << "Content-Length: " << response.size() << "\r\n"; - if (lastModified) { + if (lastModified != TInstant()) { res << "Date: " << TInstant::Now().ToRfc822String() << "\r\n"; res << "Last-Modified: " << lastModified.ToRfc822String() << "\r\n"; res << "Cache-Control: max-age=604800\r\n"; // one week diff --git a/ydb/core/viewer/viewer.h b/ydb/core/viewer/viewer.h index e63360ce457a..4fa5cef0ce5e 100644 --- a/ydb/core/viewer/viewer.h +++ b/ydb/core/viewer/viewer.h @@ -169,9 +169,10 @@ class IViewer { return GetHTTPOK(request, "text/plain", response, lastModified); } - virtual TString GetHTTPGATEWAYTIMEOUT(const NMon::TEvHttpInfo* request) = 0; + virtual TString GetHTTPGATEWAYTIMEOUT(const NMon::TEvHttpInfo* request, TString contentType = {}, TString response = {}) = 0; virtual TString GetHTTPBADREQUEST(const NMon::TEvHttpInfo* request, TString contentType = {}, TString response = {}) = 0; virtual TString GetHTTPFORBIDDEN(const NMon::TEvHttpInfo* request) = 0; + virtual TString GetHTTPNOTFOUND(const NMon::TEvHttpInfo* request) = 0; }; void SetupPQVirtualHandlers(IViewer* viewer); @@ -198,6 +199,12 @@ struct TJsonRequestParameters { static YAML::Node GetParameters() { return {}; } }; +template +struct TJsonRequestSwagger { + static YAML::Node GetSwagger() { return {}; } +}; + + template void GenericSplitIds(TStringBuf source, char delim, OutputIteratorType it) { for (TStringBuf value = source.NextTok(delim); !value.empty(); value = source.NextTok(delim)) { diff --git a/ydb/core/viewer/ya.make b/ydb/core/viewer/ya.make index a392917f7420..d743d1ee12a1 100644 --- a/ydb/core/viewer/ya.make +++ b/ydb/core/viewer/ya.make @@ -24,6 +24,7 @@ SRCS( json_local_rpc.h json_getblob.h json_graph.h + json_handlers_pdisk.cpp json_handlers_vdisk.cpp json_handlers_viewer.cpp json_healthcheck.h diff --git a/ydb/library/actors/http/http_static.cpp b/ydb/library/actors/http/http_static.cpp index 7f6321def38d..3bd56d40be6c 100644 --- a/ydb/library/actors/http/http_static.cpp +++ b/ydb/library/actors/http/http_static.cpp @@ -29,7 +29,7 @@ class THttpStaticContentHandler : public NActors::TActor