diff options
author | Alexander Rutkovsky <alexvru@mail.ru> | 2022-03-15 16:41:43 +0300 |
---|---|---|
committer | Alexander Rutkovsky <alexvru@mail.ru> | 2022-03-15 16:41:43 +0300 |
commit | d594eb68063ba68b202dda9ab4a3f91bda0383f7 (patch) | |
tree | 108e4c98c2bfa8666b16ff4fd888fdb38342848e | |
parent | 2ccb6d477d51a6dcc6be37330b6cb6c62a935a35 (diff) | |
download | ydb-d594eb68063ba68b202dda9ab4a3f91bda0383f7.tar.gz |
Support BS configuration via HTTP KIKIMR-14300
ref:ffd1adb28bace088d0186707688f5e4a9fadf114
-rw-r--r-- | ydb/core/mind/bscontroller/impl.h | 1 | ||||
-rw-r--r-- | ydb/core/mind/bscontroller/monitoring.cpp | 111 |
2 files changed, 112 insertions, 0 deletions
diff --git a/ydb/core/mind/bscontroller/impl.h b/ydb/core/mind/bscontroller/impl.h index 2cf3989ca4..9e409917f6 100644 --- a/ydb/core/mind/bscontroller/impl.h +++ b/ydb/core/mind/bscontroller/impl.h @@ -1521,6 +1521,7 @@ private: void OnActivateExecutor(const TActorContext&) override; bool OnRenderAppHtmlPage(NMon::TEvRemoteHttpInfo::TPtr ev, const TActorContext&) override; + void ProcessPostQuery(const NActorsProto::TRemoteHttpInfo& query, TActorId sender); void RenderResourceValues(IOutputStream& out, const TResourceRawValues& current); void RenderHeader(IOutputStream& out); diff --git a/ydb/core/mind/bscontroller/monitoring.cpp b/ydb/core/mind/bscontroller/monitoring.cpp index 37b9400193..1e1ab9663f 100644 --- a/ydb/core/mind/bscontroller/monitoring.cpp +++ b/ydb/core/mind/bscontroller/monitoring.cpp @@ -613,6 +613,113 @@ public: ) }; +void TBlobStorageController::ProcessPostQuery(const NActorsProto::TRemoteHttpInfo& query, TActorId sender) { + THttpHeaders headers; + for (const auto& header : query.GetHeaders()) { + headers.AddHeader(header.GetName(), header.GetValue()); + } + + TCgiParameters params; + for (const auto& param : query.GetQueryParams()) { + params.emplace(param.GetKey(), param.GetValue()); + } + for (const auto& param : query.GetPostParams()) { + params.emplace(param.GetKey(), param.GetValue()); + } + + auto sendResponse = [&](TString message, TString contentType, TString content) { + Send(sender, new NMon::TEvRemoteBinaryInfoRes(TStringBuilder() << "HTTP/1.1 " << message << "\r\n" + "Content-Type: " << contentType << "\r\n" + "\r\n" << content)); + }; + + if (params.count("exec")) { + auto request = std::make_unique<TEvBlobStorage::TEvControllerConfigRequest>(); + auto *record = request->Record.MutableRequest(); + + TString contentType; + if (const auto *header = headers.FindHeader("Content-Type")) { + TStringBuf value = header->Value(); + contentType = value.NextTok(';'); + } + bool success = false; + if (contentType == "application/x-protobuf-text") { + NProtoBuf::TextFormat::Parser parser; + success = parser.ParseFromString(query.GetPostContent(), record); + } else if (contentType == "application/x-protobuf") { + success = record->ParseFromString(query.GetPostContent()); + } else if (contentType == "application/json") { + const auto status = google::protobuf::util::JsonStringToMessage(query.GetPostContent(), record); + success = status.ok(); + } else { + return sendResponse("400 Bad request", "text/plain", "unsupported Content-Type header value"); + } + if (!success) { + return sendResponse("400 Bad request", "text/plain", "failed to parse request"); + } + + TString accept = "application/x-protobuf-text"; + if (const auto *header = headers.FindHeader("Accept")) { + accept = header->Value(); + if (accept == "*/*") { + accept = "application/x-protobuf-text"; + } + if (accept != "application/x-protobuf-text" && accept != "application/x-protobuf" && accept != "application/json") { + return sendResponse("400 Bad request", "text/plain", "unsupported Accept header value"); + } + } + + if (request) { + class TQueryExecActor : public TActor<TQueryExecActor> { + const TActorId Sender; + const TString Accept; + + public: + TQueryExecActor(const TActorId& sender, const TString& accept) + : TActor(&TThis::StateFunc) + , Sender(sender) + , Accept(accept) + {} + + STRICT_STFUNC(StateFunc, + hFunc(TEvBlobStorage::TEvControllerConfigResponse, Handle) + ) + + void Handle(TEvBlobStorage::TEvControllerConfigResponse::TPtr ev) { + const auto& response = ev->Get()->Record.GetResponse(); + + TStringStream s; + s << "HTTP/1.1 200 OK\r\n" + "Content-Type: " << Accept << "\r\n" + "\r\n"; + + TString data; + + if (Accept == "application/x-protobuf-text") { + NProtoBuf::TextFormat::Printer p; + p.SetSingleLineMode(true); + p.PrintToString(response, &data); + } else if (Accept == "application/x-protobuf") { + const bool success = response.SerializeToString(&data); + Y_VERIFY(success); + } else if (Accept == "application/json") { + google::protobuf::util::MessageToJsonString(response, &data); + } else { + Y_FAIL(); + } + s << data; + + Send(Sender, new NMon::TEvRemoteBinaryInfoRes(s.Str())); + PassAway(); + } + }; + + const TActorId& processorId = Register(new TQueryExecActor(sender, accept)); + TActivationContext::Send(new IEventHandle(SelfId(), processorId, request.release())); + } + } +} + bool TBlobStorageController::OnRenderAppHtmlPage(NMon::TEvRemoteHttpInfo::TPtr ev, const TActorContext&) { if (!Executor() || !Executor()->GetStats().IsActive) { return false; @@ -620,6 +727,10 @@ bool TBlobStorageController::OnRenderAppHtmlPage(NMon::TEvRemoteHttpInfo::TPtr e if (!ev) { return true; } + if (const auto& ext = ev->Get()->ExtendedQuery; ext && ext->GetMethod() == HTTP_METHOD_POST) { + ProcessPostQuery(*ext, ev->Sender); + return true; + } THolder<TTransactionBase<TBlobStorageController>> tx; TStringStream str; |