|
| 1 | +#pragma once |
| 2 | +#include <ydb/library/actors/core/actor_bootstrapped.h> |
| 3 | +#include <ydb/library/actors/core/interconnect.h> |
| 4 | +#include <ydb/library/actors/core/mon.h> |
| 5 | +#include <ydb/library/services/services.pb.h> |
| 6 | +#include <ydb/core/viewer/json/json.h> |
| 7 | +#include <ydb/core/viewer/yaml/yaml.h> |
| 8 | +#include <ydb/core/util/wildcard.h> |
| 9 | +#include <library/cpp/json/json_writer.h> |
| 10 | +#include "viewer.h" |
| 11 | +#include "json_pipe_req.h" |
| 12 | + |
| 13 | +namespace NKikimr { |
| 14 | +namespace NViewer { |
| 15 | + |
| 16 | +using namespace NActors; |
| 17 | + |
| 18 | +class TPDiskInfo : public TViewerPipeClient<TPDiskInfo> { |
| 19 | + enum EEv { |
| 20 | + EvRetryNodeRequest = EventSpaceBegin(NActors::TEvents::ES_PRIVATE), |
| 21 | + EvEnd |
| 22 | + }; |
| 23 | + |
| 24 | + static_assert(EvEnd < EventSpaceEnd(NActors::TEvents::ES_PRIVATE), "expect EvEnd < EventSpaceEnd(TEvents::ES_PRIVATE)"); |
| 25 | + |
| 26 | + struct TEvRetryNodeRequest : NActors::TEventLocal<TEvRetryNodeRequest, EvRetryNodeRequest> { |
| 27 | + TEvRetryNodeRequest() |
| 28 | + {} |
| 29 | + }; |
| 30 | + |
| 31 | +protected: |
| 32 | + using TThis = TPDiskInfo; |
| 33 | + using TBase = TViewerPipeClient<TThis>; |
| 34 | + IViewer* Viewer; |
| 35 | + NMon::TEvHttpInfo::TPtr Event; |
| 36 | + ui32 Timeout = 0; |
| 37 | + ui32 ActualRetries = 0; |
| 38 | + ui32 Retries = 0; |
| 39 | + TDuration RetryPeriod = TDuration::MilliSeconds(500); |
| 40 | + |
| 41 | + std::unique_ptr<NSysView::TEvSysView::TEvGetPDisksResponse> BSCResponse; |
| 42 | + std::unique_ptr<NNodeWhiteboard::TEvWhiteboard::TEvPDiskStateResponse> WhiteboardResponse; |
| 43 | + |
| 44 | + ui32 NodeId = 0; |
| 45 | + ui32 PDiskId = 0; |
| 46 | + |
| 47 | +public: |
| 48 | + static constexpr NKikimrServices::TActivity::EType ActorActivityType() { |
| 49 | + return NKikimrServices::TActivity::VIEWER_HANDLER; |
| 50 | + } |
| 51 | + |
| 52 | + TPDiskInfo(IViewer* viewer, NMon::TEvHttpInfo::TPtr& ev) |
| 53 | + : Viewer(viewer) |
| 54 | + , Event(ev) |
| 55 | + {} |
| 56 | + |
| 57 | + void Bootstrap() { |
| 58 | + const auto& params(Event->Get()->Request.GetParams()); |
| 59 | + NodeId = FromStringWithDefault<ui32>(params.Get("node_id"), 0); |
| 60 | + PDiskId = FromStringWithDefault<ui32>(params.Get("pdisk_id"), Max<ui32>()); |
| 61 | + |
| 62 | + if (PDiskId == Max<ui32>()) { |
| 63 | + TBase::Send(Event->Sender, new NMon::TEvHttpInfoRes( |
| 64 | + Viewer->GetHTTPBADREQUEST(Event->Get(), "text/plain", "field 'pdisk_id' is required"), |
| 65 | + 0, NMon::IEvHttpInfoRes::EContentType::Custom)); |
| 66 | + return PassAway(); |
| 67 | + } |
| 68 | + if (Event->Get()->Request.GetMethod() != HTTP_METHOD_GET) { |
| 69 | + TBase::Send(Event->Sender, new NMon::TEvHttpInfoRes( |
| 70 | + Viewer->GetHTTPBADREQUEST(Event->Get(), "text/plain", "Only GET method is allowed"), |
| 71 | + 0, NMon::IEvHttpInfoRes::EContentType::Custom)); |
| 72 | + return PassAway(); |
| 73 | + } |
| 74 | + |
| 75 | + if (!NodeId) { |
| 76 | + NodeId = TlsActivationContext->ActorSystem()->NodeId; |
| 77 | + } |
| 78 | + TBase::InitConfig(params); |
| 79 | + |
| 80 | + Timeout = FromStringWithDefault<ui32>(params.Get("timeout"), 10000); |
| 81 | + Retries = FromStringWithDefault<ui32>(params.Get("retries"), 3); |
| 82 | + RetryPeriod = TDuration::MilliSeconds(FromStringWithDefault<ui32>(params.Get("retry_period"), RetryPeriod.MilliSeconds())); |
| 83 | + |
| 84 | + SendWhiteboardRequest(); |
| 85 | + SendBSCRequest(); |
| 86 | + |
| 87 | + TBase::Become(&TThis::StateWork, TDuration::MilliSeconds(Timeout), new TEvents::TEvWakeup()); |
| 88 | + } |
| 89 | + |
| 90 | + STATEFN(StateWork) { |
| 91 | + switch (ev->GetTypeRewrite()) { |
| 92 | + hFunc(NNodeWhiteboard::TEvWhiteboard::TEvPDiskStateResponse, Handle); |
| 93 | + hFunc(NSysView::TEvSysView::TEvGetPDisksResponse, Handle); |
| 94 | + cFunc(TEvRetryNodeRequest::EventType, HandleRetry); |
| 95 | + cFunc(TEvents::TEvUndelivered::EventType, Undelivered); |
| 96 | + cFunc(TEvents::TSystem::Wakeup, HandleTimeout); |
| 97 | + } |
| 98 | + } |
| 99 | + |
| 100 | + void SendWhiteboardRequest() { |
| 101 | + TActorId whiteboardServiceId = NNodeWhiteboard::MakeNodeWhiteboardServiceId(NodeId); |
| 102 | + auto request = std::make_unique<NNodeWhiteboard::TEvWhiteboard::TEvPDiskStateRequest>(); |
| 103 | + TBase::SendRequest(whiteboardServiceId, request.release(), IEventHandle::FlagTrackDelivery | IEventHandle::FlagSubscribeOnSession, NodeId); |
| 104 | + } |
| 105 | + |
| 106 | + void SendBSCRequest() { |
| 107 | + RequestBSControllerPDiskInfo(NodeId, PDiskId); |
| 108 | + } |
| 109 | + |
| 110 | + bool RetryRequest() { |
| 111 | + if (Retries) { |
| 112 | + if (++ActualRetries <= Retries) { |
| 113 | + TBase::Schedule(RetryPeriod, new TEvRetryNodeRequest()); |
| 114 | + return true; |
| 115 | + } |
| 116 | + } |
| 117 | + return false; |
| 118 | + } |
| 119 | + |
| 120 | + void Undelivered() { |
| 121 | + if (!RetryRequest()) { |
| 122 | + TBase::RequestDone(); |
| 123 | + } |
| 124 | + } |
| 125 | + |
| 126 | + void Handle(NSysView::TEvSysView::TEvGetPDisksResponse::TPtr& ev) { |
| 127 | + BSCResponse.reset(ev->Release().Release()); |
| 128 | + TBase::RequestDone(); |
| 129 | + } |
| 130 | + |
| 131 | + void Handle(NNodeWhiteboard::TEvWhiteboard::TEvPDiskStateResponse::TPtr& ev) { |
| 132 | + WhiteboardResponse.reset(ev->Release().Release()); |
| 133 | + TBase::RequestDone(); |
| 134 | + } |
| 135 | + |
| 136 | + void HandleRetry() { |
| 137 | + SendWhiteboardRequest(); |
| 138 | + } |
| 139 | + |
| 140 | + void HandleTimeout() { |
| 141 | + Send(Event->Sender, new NMon::TEvHttpInfoRes( |
| 142 | + Viewer->GetHTTPGATEWAYTIMEOUT(Event->Get(), "text/plain", "Timeout receiving response from NodeWarden"), |
| 143 | + 0, NMon::IEvHttpInfoRes::EContentType::Custom)); |
| 144 | + } |
| 145 | + |
| 146 | + void PassAway() override { |
| 147 | + TBase::Send(TActivationContext::InterconnectProxy(NodeId), new TEvents::TEvUnsubscribe()); |
| 148 | + TBase::PassAway(); |
| 149 | + } |
| 150 | + |
| 151 | + void ReplyAndPassAway() { |
| 152 | + NKikimrViewer::TPDiskInfo proto; |
| 153 | + TStringStream json; |
| 154 | + if (WhiteboardResponse != nullptr && WhiteboardResponse->Record.PDiskStateInfoSize() > 0) { |
| 155 | + proto.MutableWhiteboard()->CopyFrom(WhiteboardResponse->Record.GetPDiskStateInfo(0)); |
| 156 | + } |
| 157 | + if (BSCResponse != nullptr && BSCResponse->Record.EntriesSize() > 0) { |
| 158 | + proto.MutableBSC()->CopyFrom(BSCResponse->Record.GetEntries(0).GetInfo()); |
| 159 | + } |
| 160 | + TProtoToJson::ProtoToJson(json, proto, { |
| 161 | + .EnumAsNumbers = false, |
| 162 | + }); |
| 163 | + TBase::Send(Event->Sender, new NMon::TEvHttpInfoRes(Viewer->GetHTTPOKJSON(Event->Get(), json.Str()), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); |
| 164 | + PassAway(); |
| 165 | + } |
| 166 | +}; |
| 167 | + |
| 168 | +template <> |
| 169 | +YAML::Node TJsonRequestSwagger<TPDiskInfo>::GetSwagger() { |
| 170 | + YAML::Node node = YAML::Load(R"___( |
| 171 | + get: |
| 172 | + tags: |
| 173 | + - pdisk |
| 174 | + summary: Gets PDisk info |
| 175 | + description: Gets PDisk information from Whiteboard and BSC |
| 176 | + parameters: |
| 177 | + - name: node_id |
| 178 | + in: query |
| 179 | + description: node identifier |
| 180 | + type: integer |
| 181 | + - name: pdisk_id |
| 182 | + in: query |
| 183 | + description: pdisk identifier |
| 184 | + required: true |
| 185 | + type: integer |
| 186 | + - name: timeout |
| 187 | + in: query |
| 188 | + description: timeout in ms |
| 189 | + required: false |
| 190 | + type: integer |
| 191 | + responses: |
| 192 | + 200: |
| 193 | + description: OK |
| 194 | + content: |
| 195 | + application/json: |
| 196 | + schema: {} |
| 197 | + 400: |
| 198 | + description: Bad Request |
| 199 | + 403: |
| 200 | + description: Forbidden |
| 201 | + 504: |
| 202 | + description: Gateway Timeout |
| 203 | + )___"); |
| 204 | + |
| 205 | + node["get"]["responses"]["200"]["content"]["application/json"]["schema"] = TProtoToYaml::ProtoToYamlSchema<NKikimrViewer::TPDiskInfo>(); |
| 206 | + YAML::Node properties(node["get"]["responses"]["200"]["content"]["application/json"]["schema"]["properties"]["BSC"]["properties"]); |
| 207 | + TProtoToYaml::FillEnum(properties["StatusV2"], NProtoBuf::GetEnumDescriptor<NKikimrBlobStorage::EDriveStatus>()); |
| 208 | + TProtoToYaml::FillEnum(properties["DecommitStatus"], NProtoBuf::GetEnumDescriptor<NKikimrBlobStorage::EDecommitStatus>()); |
| 209 | + TProtoToYaml::FillEnum(properties["Type"], NProtoBuf::GetEnumDescriptor<NKikimrBlobStorage::EPDiskType>()); |
| 210 | + return node; |
| 211 | +} |
| 212 | + |
| 213 | +} |
| 214 | +} |
0 commit comments