aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Rutkovsky <alexvru@mail.ru>2022-03-15 16:41:43 +0300
committerAlexander Rutkovsky <alexvru@mail.ru>2022-03-15 16:41:43 +0300
commitd594eb68063ba68b202dda9ab4a3f91bda0383f7 (patch)
tree108e4c98c2bfa8666b16ff4fd888fdb38342848e
parent2ccb6d477d51a6dcc6be37330b6cb6c62a935a35 (diff)
downloadydb-d594eb68063ba68b202dda9ab4a3f91bda0383f7.tar.gz
Support BS configuration via HTTP KIKIMR-14300
ref:ffd1adb28bace088d0186707688f5e4a9fadf114
-rw-r--r--ydb/core/mind/bscontroller/impl.h1
-rw-r--r--ydb/core/mind/bscontroller/monitoring.cpp111
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;