Skip to content

Commit dd7fedd

Browse files
authored
stable-25-3-1: Implement display of s3 configuration in mon page (#29848)
2 parents 0b70c78 + 4346834 commit dd7fedd

File tree

2 files changed

+160
-0
lines changed

2 files changed

+160
-0
lines changed

ydb/core/blob_depot/blob_depot_tablet.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@ namespace NKikimr::NBlobDepot {
302302
// Monitoring
303303

304304
class TTxMonData;
305+
class TTxMonS3Config;
305306

306307
TJsonHandler JsonHandler;
307308

ydb/core/blob_depot/mon_main.cpp

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
#include "space_monitor.h"
66
#include "mon_main.h"
77
#include "s3.h"
8+
#include "types.h"
9+
#include <ydb/public/api/protos/ydb_export.pb.h>
10+
#include <ydb/core/protos/s3_settings.pb.h>
11+
#include <ydb/core/protos/blob_depot_config.pb.h>
812

913
namespace NKikimr::NBlobDepot {
1014

@@ -85,6 +89,7 @@ namespace NKikimr::NBlobDepot {
8589
}
8690

8791
HTML(Stream) {
92+
Stream << "<a href='app?TabletID=" << Self->TabletID() << "'>Back to main page</a>";
8893
DIV_CLASS("panel panel-info") {
8994
DIV_CLASS("panel-heading") {
9095
Stream << "Data";
@@ -380,6 +385,153 @@ namespace NKikimr::NBlobDepot {
380385
}
381386
};
382387

388+
class TBlobDepot::TTxMonS3Config : public NTabletFlatExecutor::TTransactionBase<TBlobDepot> {
389+
std::unique_ptr<NMon::TEvRemoteHttpInfo::THandle> Request;
390+
TStringStream Stream;
391+
392+
public:
393+
TTxType GetTxType() const override { return NKikimrBlobDepot::TXTYPE_MON_DATA; }
394+
395+
TTxMonS3Config(TBlobDepot *self, NMon::TEvRemoteHttpInfo::TPtr ev)
396+
: TTransactionBase(self)
397+
, Request(ev.Release())
398+
{}
399+
400+
bool Execute(TTransactionContext& /*txc*/, const TActorContext&) override {
401+
HTML(Stream) {
402+
Stream << "<a href='app?TabletID=" << Self->TabletID() << "'>Back to main page</a>";
403+
DIV_CLASS("panel panel-info") {
404+
DIV_CLASS("panel-heading") {
405+
Stream << "S3 Configuration";
406+
}
407+
DIV_CLASS("panel-body") {
408+
TABLE_CLASS("table") {
409+
TABLEHEAD() {
410+
TABLER() {
411+
TABLEH() { Stream << "Setting"; }
412+
TABLEH() { Stream << "Value"; }
413+
}
414+
}
415+
TABLEBODY() {
416+
// Check if S3 is configured
417+
if (!Self->Config.HasS3BackendSettings()) {
418+
TABLER() {
419+
TABLED() { Stream << "Status"; }
420+
TABLED() { Stream << "S3 not configured"; }
421+
}
422+
return true;
423+
}
424+
425+
const auto& s3BackendSettings = Self->Config.GetS3BackendSettings();
426+
427+
#define BD_MON_TABLE_ROW(key, value) \
428+
do { \
429+
TABLER() { \
430+
TABLED() { Stream << key ;} \
431+
TABLED() { Stream << value ;} \
432+
} \
433+
} while(false)
434+
435+
#define BD_MON_TABLE_ROW_WITH_FORMATTER(config, key, formatter) \
436+
do { \
437+
if (config.Has##key()) { \
438+
BD_MON_TABLE_ROW(#key, formatter(config.Get##key())); \
439+
} \
440+
} while(false)
441+
442+
443+
if (!s3BackendSettings.HasSettings()) {
444+
BD_MON_TABLE_ROW("Status", "S3 settings not configured");
445+
return true;
446+
}
447+
448+
const auto& s3Settings = s3BackendSettings.GetSettings();
449+
450+
TString mode;
451+
if (s3BackendSettings.HasAsyncMode()) {
452+
mode = "Async";
453+
} else if (s3BackendSettings.HasSyncMode()) {
454+
mode = "Sync";
455+
} else {
456+
mode = "Unknown";
457+
}
458+
BD_MON_TABLE_ROW("Mode", mode);
459+
460+
auto id_formatter = [] (auto x) { return x; };
461+
462+
// Display async mode settings if applicable
463+
if (s3BackendSettings.HasAsyncMode()) {
464+
const auto& asyncMode = s3BackendSettings.GetAsyncMode();
465+
466+
auto formatBytePerSecond = [](ui64 bytes) -> TString {
467+
return FormatByteSize(bytes) + "/s";
468+
};
469+
470+
BD_MON_TABLE_ROW_WITH_FORMATTER(asyncMode, MaxPendingBytes, FormatByteSize);
471+
BD_MON_TABLE_ROW_WITH_FORMATTER(asyncMode, ThrottleStartBytes, FormatByteSize);
472+
BD_MON_TABLE_ROW_WITH_FORMATTER(asyncMode, ThrottleMaxBytesPerSecond, formatBytePerSecond);
473+
BD_MON_TABLE_ROW_WITH_FORMATTER(asyncMode, UploadPutsInFlight, id_formatter);
474+
475+
}
476+
477+
BD_MON_TABLE_ROW("Endpoint", s3Settings.GetEndpoint());
478+
479+
TString schemeStr;
480+
if (s3Settings.HasScheme()) {
481+
switch (s3Settings.GetScheme()) {
482+
case NKikimrSchemeOp::TS3Settings::HTTPS:
483+
schemeStr = "https";
484+
break;
485+
case NKikimrSchemeOp::TS3Settings::HTTP:
486+
schemeStr = "http";
487+
break;
488+
}
489+
} else {
490+
schemeStr = "unspecified";
491+
}
492+
BD_MON_TABLE_ROW("Scheme", schemeStr);
493+
494+
BD_MON_TABLE_ROW("Bucket", s3Settings.GetBucket());
495+
496+
// Helper function to mask sensitive data
497+
auto maskSensitive = [](const TString& value) -> TString {
498+
if (value.empty()) {
499+
return value;
500+
}
501+
if (value.size() <= 12) {
502+
return TString(4, '*');
503+
}
504+
return value.substr(0, 2) + "****" + value.substr(value.size() - 2);
505+
};
506+
BD_MON_TABLE_ROW("AccessKey", maskSensitive(s3Settings.GetAccessKey()));
507+
BD_MON_TABLE_ROW("SecretKey", maskSensitive(s3Settings.GetSecretKey()));
508+
509+
BD_MON_TABLE_ROW_WITH_FORMATTER(s3Settings, Region, id_formatter);
510+
BD_MON_TABLE_ROW_WITH_FORMATTER(s3Settings, StorageClass, Ydb::Export::ExportToS3Settings::StorageClass_Name);
511+
BD_MON_TABLE_ROW_WITH_FORMATTER(s3Settings, UseVirtualAddressing, ToString);
512+
BD_MON_TABLE_ROW_WITH_FORMATTER(s3Settings, VerifySSL, ToString);
513+
BD_MON_TABLE_ROW_WITH_FORMATTER(s3Settings, ProxyHost, id_formatter);
514+
BD_MON_TABLE_ROW_WITH_FORMATTER(s3Settings, ProxyPort, id_formatter);
515+
BD_MON_TABLE_ROW_WITH_FORMATTER(s3Settings, ConnectionTimeoutMs, id_formatter);
516+
BD_MON_TABLE_ROW_WITH_FORMATTER(s3Settings, RequestTimeoutMs, id_formatter);
517+
BD_MON_TABLE_ROW_WITH_FORMATTER(s3Settings, HttpRequestTimeoutMs, id_formatter);
518+
BD_MON_TABLE_ROW_WITH_FORMATTER(s3Settings, ExecutorThreadsCount, id_formatter);
519+
BD_MON_TABLE_ROW_WITH_FORMATTER(s3Settings, MaxConnectionsCount, id_formatter);
520+
}
521+
}
522+
}
523+
}
524+
}
525+
526+
return true;
527+
}
528+
529+
void Complete(const TActorContext&) override {
530+
TActivationContext::Send(new IEventHandle(Request->Sender, Self->SelfId(), new NMon::TEvRemoteHttpInfoRes(
531+
Stream.Str()), 0, Request->Cookie));
532+
}
533+
};
534+
383535
bool TBlobDepot::OnRenderAppHtmlPage(NMon::TEvRemoteHttpInfo::TPtr ev, const TActorContext&) {
384536
if (!Executor() || !Executor()->GetStats().IsActive) {
385537
return false;
@@ -399,6 +551,9 @@ namespace NKikimr::NBlobDepot {
399551
if (page == "data") {
400552
Execute(std::make_unique<TTxMonData>(this, ev));
401553
return true;
554+
} if (page == "s3config") {
555+
Execute(std::make_unique<TTxMonS3Config>(this, ev));
556+
return true;
402557
} else {
403558
Send(ev->Sender, new NMon::TEvRemoteBinaryInfoRes(TStringBuilder()
404559
<< "HTTP/1.1 403 Page not found\r\n"
@@ -418,6 +573,10 @@ namespace NKikimr::NBlobDepot {
418573

419574
void TBlobDepot::RenderMainPage(IOutputStream& s) {
420575
HTML(s) {
576+
if (S3Manager) {
577+
s << "<a href='app?TabletID=" << TabletID() << "&page=s3config'>S3 config</a><br>";
578+
}
579+
421580
s << "<a href='app?TabletID=" << TabletID() << "&page=data'>Contained data</a><br>";
422581

423582
s << R"(<script>

0 commit comments

Comments
 (0)