aboutsummaryrefslogtreecommitdiff
path: root/src/zenserver/admin/admin.cpp
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2025-10-14 11:32:16 +0200
committerGitHub Enterprise <[email protected]>2025-10-14 11:32:16 +0200
commitca09abbeef5b1788f4a52b61eedd2f3dd07f81f2 (patch)
tree005a50adfddf6982bab3a06bb93d4c50da1a11fd /src/zenserver/admin/admin.cpp
parentmake asiohttp work without IPv6 (#562) (diff)
downloadzen-ca09abbeef5b1788f4a52b61eedd2f3dd07f81f2.tar.xz
zen-ca09abbeef5b1788f4a52b61eedd2f3dd07f81f2.zip
move all storage-related services into storage tree (#571)
* move all storage-related services into storage tree * move config into config/ * also move admin service into storage since it mostly has storage related functionality * header consolidation
Diffstat (limited to 'src/zenserver/admin/admin.cpp')
-rw-r--r--src/zenserver/admin/admin.cpp805
1 files changed, 0 insertions, 805 deletions
diff --git a/src/zenserver/admin/admin.cpp b/src/zenserver/admin/admin.cpp
deleted file mode 100644
index 97522e892..000000000
--- a/src/zenserver/admin/admin.cpp
+++ /dev/null
@@ -1,805 +0,0 @@
-// Copyright Epic Games, Inc. All Rights Reserved.
-
-#include "admin.h"
-
-#include <zencore/compactbinarybuilder.h>
-#include <zencore/filesystem.h>
-#include <zencore/fmtutils.h>
-#include <zencore/jobqueue.h>
-#include <zencore/logging.h>
-#include <zencore/string.h>
-
-#if ZEN_WITH_TRACE
-# include <zencore/trace.h>
-#endif // ZEN_WITH_TRACE
-
-#if ZEN_USE_MIMALLOC
-# include <mimalloc.h>
-#endif
-
-#include <zenstore/gc.h>
-
-#include <zenstore/cache/structuredcachestore.h>
-#include <zenutil/workerpools.h>
-#include "config.h"
-
-#include <chrono>
-
-namespace zen {
-
-struct DirStats
-{
- uint64_t FileCount = 0;
- uint64_t DirCount = 0;
- uint64_t ByteCount = 0;
-};
-
-DirStats
-GetStatsForDirectory(std::filesystem::path Dir)
-{
- if (!IsDir(Dir))
- return {};
-
- struct StatsTraversal : public GetDirectoryContentVisitor
- {
- virtual void AsyncVisitDirectory(const std::filesystem::path& RelativeRoot, DirectoryContent&& Content) override
- {
- ZEN_UNUSED(RelativeRoot);
-
- uint64_t FileCount = Content.FileNames.size();
- uint64_t DirCount = Content.DirectoryNames.size();
- uint64_t FilesSize = 0;
- for (uint64_t FileSize : Content.FileSizes)
- {
- FilesSize += FileSize;
- }
- TotalBytes += FilesSize;
- TotalFileCount += FileCount;
- TotalDirCount += DirCount;
- }
-
- std::atomic_uint64_t TotalBytes = 0;
- std::atomic_uint64_t TotalFileCount = 0;
- std::atomic_uint64_t TotalDirCount = 0;
-
- DirStats GetStats()
- {
- return {.FileCount = TotalFileCount.load(), .DirCount = TotalDirCount.load(), .ByteCount = TotalBytes.load()};
- }
- } DirTraverser;
-
- Latch PendingWorkCount(1);
-
- GetDirectoryContent(Dir,
- DirectoryContentFlags::IncludeAllEntries | DirectoryContentFlags::IncludeFileSizes,
- DirTraverser,
- GetSmallWorkerPool(EWorkloadType::Background),
- PendingWorkCount);
- PendingWorkCount.CountDown();
- PendingWorkCount.Wait();
-
- return DirTraverser.GetStats();
-}
-
-struct StateDiskStats
-{
- DirStats CacheStats;
- DirStats CasStats;
- DirStats ProjectStats;
-};
-
-StateDiskStats
-GetStatsForStateDirectory(std::filesystem::path StateDir)
-{
- StateDiskStats Stats;
- Stats.CacheStats = GetStatsForDirectory(StateDir / "cache");
- Stats.CasStats = GetStatsForDirectory(StateDir / "cas");
- Stats.ProjectStats = GetStatsForDirectory(StateDir / "projects");
- return Stats;
-}
-
-HttpAdminService::HttpAdminService(GcScheduler& Scheduler,
- JobQueue& BackgroundJobQueue,
- ZenCacheStore* CacheStore,
- std::function<void()>&& FlushFunction,
- const LogPaths& LogPaths,
- const ZenServerOptions& ServerOptions)
-: m_GcScheduler(Scheduler)
-, m_BackgroundJobQueue(BackgroundJobQueue)
-, m_CacheStore(CacheStore)
-, m_FlushFunction(std::move(FlushFunction))
-, m_LogPaths(LogPaths)
-, m_ServerOptions(ServerOptions)
-{
- using namespace std::literals;
-
- m_Router.RegisterRoute(
- "health",
- [](HttpRouterRequest& Req) {
- CbObjectWriter Obj;
- Obj.AddBool("ok", true);
- Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Obj.Save());
- },
- HttpVerb::kGet);
-
- m_Router.AddPattern("jobid", "([[:digit:]]+?)");
-
- m_Router.RegisterRoute(
- "jobs",
- [&](HttpRouterRequest& Req) {
- std::vector<JobQueue::JobInfo> Jobs = m_BackgroundJobQueue.GetJobs();
- CbObjectWriter Obj;
- Obj.BeginArray("jobs");
- for (const auto& Job : Jobs)
- {
- Obj.BeginObject();
- Obj.AddInteger("Id", Job.Id.Id);
- Obj.AddString("Status", JobQueue::ToString(Job.Status));
- Obj.EndObject();
- }
- Obj.EndArray();
- Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Obj.Save());
- },
- HttpVerb::kGet);
-
- m_Router.RegisterRoute(
- "jobs/{jobid}",
- [&](HttpRouterRequest& Req) {
- const auto& JobIdString = Req.GetCapture(1);
- std::optional<uint64_t> JobIdArg = ParseInt<uint64_t>(JobIdString);
- if (!JobIdArg)
- {
- Req.ServerRequest().WriteResponse(HttpResponseCode::BadRequest);
- }
- JobId Id{.Id = JobIdArg.value_or(0)};
- if (Id.Id == 0)
- {
- return Req.ServerRequest().WriteResponse(HttpResponseCode::BadRequest,
- ZenContentType::kText,
- fmt::format("Invalid Job Id: {}", Id.Id));
- }
-
- std::optional<JobQueue::JobDetails> CurrentState = m_BackgroundJobQueue.Get(Id);
- if (!CurrentState)
- {
- return Req.ServerRequest().WriteResponse(HttpResponseCode::NotFound);
- }
-
- auto WriteState = [](CbObjectWriter& Obj, const JobQueue::State& State) {
- if (!State.CurrentOp.empty())
- {
- Obj.AddString(
- "CurrentOp"sv,
- State.CurrentOpDetails.empty() ? State.CurrentOp : fmt::format("{}: {}", State.CurrentOp, State.CurrentOpDetails));
- Obj.AddString("Op"sv, State.CurrentOp);
- if (!State.CurrentOpDetails.empty())
- {
- Obj.AddString("Details"sv, State.CurrentOpDetails);
- }
- Obj.AddInteger("TotalCount"sv, gsl::narrow<uint64_t>(State.TotalCount));
- Obj.AddInteger("RemainingCount"sv, gsl::narrow<uint64_t>(State.RemainingCount));
- Obj.AddInteger("CurrentOpPercentComplete"sv,
- State.TotalCount > 0
- ? gsl::narrow<uint32_t>((100 * (State.TotalCount - State.RemainingCount)) / State.TotalCount)
- : 0);
- }
- if (!State.Messages.empty())
- {
- Obj.BeginArray("Messages");
- for (const std::string& Message : State.Messages)
- {
- Obj.AddString(Message);
- }
- Obj.EndArray();
- }
- if (!State.AbortReason.empty())
- {
- Obj.AddString("AbortReason"sv, State.AbortReason);
- }
- };
-
- auto GetAgeAsSeconds = [](std::chrono::system_clock::time_point Start, std::chrono::system_clock::time_point End) {
- auto Age = End - Start;
- auto Milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(Age);
- return Milliseconds.count() / 1000.0;
- };
-
- const std::chrono::system_clock::time_point Now = std::chrono::system_clock::now();
-
- switch (CurrentState->Status)
- {
- case JobQueue::Status::Queued:
- {
- CbObjectWriter Obj;
- Obj.AddString("Name"sv, CurrentState->Name);
- Obj.AddString("Status"sv, "Queued"sv);
- Obj.AddFloat("QueueTimeS", GetAgeAsSeconds(CurrentState->CreateTime, Now));
- Obj.AddInteger("WorkerThread", CurrentState->WorkerThreadId);
- Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Obj.Save());
- }
- break;
- case JobQueue::Status::Running:
- {
- CbObjectWriter Obj;
- Obj.AddString("Name"sv, CurrentState->Name);
- Obj.AddString("Status"sv, "Running"sv);
- WriteState(Obj, CurrentState->State);
- Obj.AddFloat("QueueTimeS", GetAgeAsSeconds(CurrentState->CreateTime, CurrentState->StartTime));
- Obj.AddFloat("RunTimeS", GetAgeAsSeconds(CurrentState->StartTime, Now));
- Obj.AddInteger("WorkerThread", CurrentState->WorkerThreadId);
- Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Obj.Save());
- }
- break;
- case JobQueue::Status::Aborted:
- {
- CbObjectWriter Obj;
- Obj.AddString("Name"sv, CurrentState->Name);
- Obj.AddString("Status"sv, "Aborted"sv);
-
- WriteState(Obj, CurrentState->State);
- Obj.AddFloat("QueueTimeS", GetAgeAsSeconds(CurrentState->CreateTime, CurrentState->StartTime));
- Obj.AddFloat("RunTimeS", GetAgeAsSeconds(CurrentState->StartTime, CurrentState->EndTime));
- Obj.AddFloat("CompleteTimeS", GetAgeAsSeconds(CurrentState->EndTime, Now));
- Obj.AddInteger("ReturnCode", CurrentState->ReturnCode);
- Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Obj.Save());
- }
- break;
- case JobQueue::Status::Completed:
- {
- CbObjectWriter Obj;
- Obj.AddString("Name"sv, CurrentState->Name);
- Obj.AddString("Status"sv, "Complete"sv);
- WriteState(Obj, CurrentState->State);
- Obj.AddFloat("QueueTimeS", GetAgeAsSeconds(CurrentState->CreateTime, CurrentState->StartTime));
- Obj.AddFloat("RunTimeS", GetAgeAsSeconds(CurrentState->StartTime, CurrentState->EndTime));
- Obj.AddFloat("CompleteTimeS", GetAgeAsSeconds(CurrentState->EndTime, Now));
- Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Obj.Save());
- }
- break;
- }
- },
- HttpVerb::kGet);
-
- m_Router.RegisterRoute(
- "jobs/{jobid}",
- [&](HttpRouterRequest& Req) {
- const auto& JobIdString = Req.GetCapture(1);
- std::optional<uint64_t> JobIdArg = ParseInt<uint64_t>(JobIdString);
- if (!JobIdArg)
- {
- Req.ServerRequest().WriteResponse(HttpResponseCode::BadRequest);
- }
- JobId Id{.Id = JobIdArg.value_or(0)};
- if (m_BackgroundJobQueue.CancelJob(Id))
- {
- Req.ServerRequest().WriteResponse(HttpResponseCode::OK);
- }
- else
- {
- Req.ServerRequest().WriteResponse(HttpResponseCode::NotFound);
- }
- },
- HttpVerb::kDelete);
-
- m_Router.RegisterRoute(
- "gc",
- [this](HttpRouterRequest& Req) {
- const GcSchedulerState State = m_GcScheduler.GetState();
-
- const HttpServerRequest::QueryParams Params = Req.ServerRequest().GetQueryParams();
-
- bool Details = false;
- if (auto Param = Params.GetValue("details"); Param == "true")
- {
- Details = true;
- }
-
- CbObjectWriter Response;
- Response << "Status"sv << (GcSchedulerStatus::kIdle == State.Status ? "Idle"sv : "Running"sv);
- Response.BeginObject("Config");
- {
- Response << "RootDirectory" << State.Config.RootDirectory.string();
- Response << "MonitorInterval" << ToTimeSpan(State.Config.MonitorInterval);
- Response << "Interval" << ToTimeSpan(State.Config.Interval);
- Response << "MaxCacheDuration" << ToTimeSpan(State.Config.MaxCacheDuration);
- Response << "MaxProjectStoreDuration" << ToTimeSpan(State.Config.MaxProjectStoreDuration);
- Response << "MaxBuildStoreDuration" << ToTimeSpan(State.Config.MaxBuildStoreDuration);
- Response << "CollectSmallObjects" << State.Config.CollectSmallObjects;
- Response << "Enabled" << State.Config.Enabled;
- Response << "DiskReserveSize" << NiceBytes(State.Config.DiskReserveSize);
- Response << "DiskSizeSoftLimit" << NiceBytes(State.Config.DiskSizeSoftLimit);
- Response << "MinimumFreeDiskSpaceToAllowWrites" << NiceBytes(State.Config.MinimumFreeDiskSpaceToAllowWrites);
- Response << "LightweightInterval" << ToTimeSpan(State.Config.LightweightInterval);
- Response << "UseGCVersion" << ((State.Config.UseGCVersion == GcVersion::kV1_Deprecated) ? "1" : "2");
- Response << "CompactBlockUsageThresholdPercent" << State.Config.CompactBlockUsageThresholdPercent;
- Response << "Verbose" << State.Config.Verbose;
- Response << "SingleThreaded" << State.Config.SingleThreaded;
- Response << "AttachmentPassCount" << State.Config.AttachmentPassCount;
- }
- Response.EndObject();
- Response << "AreDiskWritesBlocked" << State.AreDiskWritesBlocked;
- Response << "HasDiskReserve" << State.HasDiskReserve;
- Response << "DiskSize" << NiceBytes(State.DiskSize);
- Response << "DiskUsed" << NiceBytes(State.DiskUsed);
- Response << "DiskFree" << NiceBytes(State.DiskFree);
-
- Response.BeginObject("FullGC");
- {
- Response << "LastTime" << ToDateTime(State.LastFullGcTime);
- Response << "TimeToNext" << ToTimeSpan(State.RemainingTimeUntilFullGc);
- if (State.Config.DiskSizeSoftLimit != 0)
- {
- Response << "SpaceToNext" << NiceBytes(State.RemainingSpaceUntilFullGC);
- }
- if (State.LastFullGCV2Result)
- {
- const bool HumanReadable = true;
- WriteGCResult(Response, State.LastFullGCV2Result.value(), HumanReadable, Details);
- }
- else
- {
- Response << "LastDuration" << ToTimeSpan(State.LastFullGcDuration);
- Response << "LastDiskFreed" << NiceBytes(State.LastFullGCDiff.DiskSize);
- Response << "LastMemoryFreed" << NiceBytes(State.LastFullGCDiff.MemorySize);
- }
- if (State.LastFullAttachmentRangeMin != IoHash::Zero || State.LastFullAttachmentRangeMax != IoHash::Max)
- {
- Response << "AttachmentRangeMin" << State.LastFullAttachmentRangeMin;
- Response << "AttachmentRangeMax" << State.LastFullAttachmentRangeMax;
- }
- }
- Response.EndObject();
- Response.BeginObject("LightweightGC");
- {
- Response << "LastTime" << ToDateTime(State.LastLightweightGcTime);
- Response << "TimeToNext" << ToTimeSpan(State.RemainingTimeUntilLightweightGc);
-
- if (State.LastLightweightGCV2Result)
- {
- const bool HumanReadable = true;
- WriteGCResult(Response, State.LastLightweightGCV2Result.value(), HumanReadable, Details);
- }
- else
- {
- Response << "LastDuration" << ToTimeSpan(State.LastLightweightGcDuration);
- Response << "LastDiskFreed" << NiceBytes(State.LastLightweightGCDiff.DiskSize);
- Response << "LastMemoryFreed" << NiceBytes(State.LastLightweightGCDiff.MemorySize);
- }
- }
- Response.EndObject();
- Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Response.Save());
- },
- HttpVerb::kGet);
-
- m_Router.RegisterRoute(
- "gc",
- [this](HttpRouterRequest& Req) {
- HttpServerRequest& HttpReq = Req.ServerRequest();
- const HttpServerRequest::QueryParams Params = HttpReq.GetQueryParams();
- GcScheduler::TriggerGcParams GcParams;
-
- if (auto Param = Params.GetValue("smallobjects"); Param.empty() == false)
- {
- GcParams.CollectSmallObjects = Param == "true"sv;
- }
-
- if (auto Param = Params.GetValue("maxcacheduration"); Param.empty() == false)
- {
- if (auto Value = ParseInt<uint64_t>(Param))
- {
- GcParams.MaxCacheDuration = std::chrono::seconds(Value.value());
- }
- }
-
- if (auto Param = Params.GetValue("maxprojectstoreduration"); Param.empty() == false)
- {
- if (auto Value = ParseInt<uint64_t>(Param))
- {
- GcParams.MaxProjectStoreDuration = std::chrono::seconds(Value.value());
- }
- }
-
- if (auto Param = Params.GetValue("maxbuildstoreduration"); Param.empty() == false)
- {
- if (auto Value = ParseInt<uint64_t>(Param))
- {
- GcParams.MaxBuildStoreDuration = std::chrono::seconds(Value.value());
- }
- }
-
- if (auto Param = Params.GetValue("disksizesoftlimit"); Param.empty() == false)
- {
- if (auto Value = ParseInt<uint64_t>(Param))
- {
- GcParams.DiskSizeSoftLimit = Value.value();
- }
- }
-
- if (auto Param = Params.GetValue("skipcid"); Param.empty() == false)
- {
- GcParams.SkipCid = Param == "true"sv;
- }
-
- if (auto Param = Params.GetValue("skipdelete"); Param.empty() == false)
- {
- GcParams.SkipDelete = Param == "true"sv;
- }
-
- if (auto Param = Params.GetValue("forceusegcv1"); Param.empty() == false)
- {
- GcParams.ForceGCVersion = GcVersion::kV1_Deprecated;
- }
-
- if (auto Param = Params.GetValue("forceusegcv2"); Param.empty() == false)
- {
- GcParams.ForceGCVersion = GcVersion::kV2;
- }
-
- if (auto Param = Params.GetValue("compactblockthreshold"); Param.empty() == false)
- {
- if (auto Value = ParseInt<uint32_t>(Param))
- {
- GcParams.CompactBlockUsageThresholdPercent = Value.value();
- }
- }
-
- if (auto Param = Params.GetValue("verbose"); Param.empty() == false)
- {
- GcParams.Verbose = Param == "true"sv;
- }
-
- if (auto Param = Params.GetValue("singlethreaded"); Param.empty() == false)
- {
- GcParams.SingleThreaded = Param == "true"sv;
- }
-
- if (auto Param = Params.GetValue("referencehashlow"); Param.empty() == false)
- {
- GcParams.AttachmentRangeMin = IoHash::FromHexString(Param);
- }
-
- if (auto Param = Params.GetValue("referencehashhigh"); Param.empty() == false)
- {
- GcParams.AttachmentRangeMax = IoHash::FromHexString(Param);
- }
-
- if (auto Param = Params.GetValue("storecacheattachmentmetadata"); Param.empty() == false)
- {
- GcParams.StoreCacheAttachmentMetaData = Param == "true"sv;
- }
-
- if (auto Param = Params.GetValue("storeprojectattachmentmetadata"); Param.empty() == false)
- {
- GcParams.StoreProjectAttachmentMetaData = Param == "true"sv;
- }
-
- if (auto Param = Params.GetValue("enablevalidation"); Param.empty() == false)
- {
- GcParams.EnableValidation = Param == "true"sv;
- }
-
- const bool Started = m_GcScheduler.TriggerGc(GcParams);
-
- CbObjectWriter Response;
- Response << "Status"sv << (Started ? "Started"sv : "Running"sv);
- HttpReq.WriteResponse(HttpResponseCode::Accepted, Response.Save());
- },
- HttpVerb::kPost);
-
- m_Router.RegisterRoute(
- "gc-stop",
- [this](HttpRouterRequest& Req) {
- HttpServerRequest& HttpReq = Req.ServerRequest();
- if (m_GcScheduler.CancelGC())
- {
- return HttpReq.WriteResponse(HttpResponseCode::Accepted);
- }
- HttpReq.WriteResponse(HttpResponseCode::OK);
- },
- HttpVerb::kPost);
-
-#if ZEN_USE_MIMALLOC
- m_Router.RegisterRoute(
- "mi_collect",
- [this](HttpRouterRequest& Req) {
- HttpServerRequest& HttpReq = Req.ServerRequest();
- const HttpServerRequest::QueryParams Params = HttpReq.GetQueryParams();
-
- bool Force = false;
-
- if (auto Param = Params.GetValue("force"); Param.empty() == false)
- {
- Force = (Param == "true"sv);
- }
-
- ExtendableStringBuilder<256> MiStats;
- ExtendableStringBuilder<256> MiStatsAfter;
-
- auto MiOutputFun = [](const char* msg, void* arg) {
- StringBuilderBase* StarsSb = reinterpret_cast<StringBuilderBase*>(arg);
- StarsSb->AppendAscii(msg);
- };
-
- mi_stats_print_out(MiOutputFun, static_cast<StringBuilderBase*>(&MiStats));
- mi_collect(Force);
- mi_stats_print_out(MiOutputFun, static_cast<StringBuilderBase*>(&MiStatsAfter));
-
- CbObjectWriter Response;
- Response << "force"sv << Force;
- Response << "stats_before"sv << MiStats;
- Response << "stats_after"sv << MiStatsAfter;
- HttpReq.WriteResponse(HttpResponseCode::OK, Response.Save());
- },
- HttpVerb::kPost);
-#endif
-
- m_Router.RegisterRoute(
- "scrub",
- [this](HttpRouterRequest& Req) {
- HttpServerRequest& HttpReq = Req.ServerRequest();
- const HttpServerRequest::QueryParams Params = HttpReq.GetQueryParams();
-
- GcScheduler::TriggerScrubParams ScrubParams;
- ScrubParams.MaxTimeslice = std::chrono::seconds(100);
-
- if (auto Param = Params.GetValue("skipdelete"); Param.empty() == false)
- {
- ScrubParams.SkipDelete = (Param == "true"sv);
- }
-
- if (auto Param = Params.GetValue("skipgc"); Param.empty() == false)
- {
- ScrubParams.SkipGc = (Param == "true"sv);
- }
-
- if (auto Param = Params.GetValue("skipcid"); Param.empty() == false)
- {
- ScrubParams.SkipCas = (Param == "true"sv);
- }
-
- m_GcScheduler.TriggerScrub(ScrubParams);
-
- CbObjectWriter Response;
- Response << "ok"sv << true;
- Response << "skip_delete" << ScrubParams.SkipDelete;
- Response << "skip_gc" << ScrubParams.SkipGc;
- Response << "skip_cas" << ScrubParams.SkipCas;
- Response << "max_time" << TimeSpan(0, 0, gsl::narrow<int>(ScrubParams.MaxTimeslice.count()));
- HttpReq.WriteResponse(HttpResponseCode::OK, Response.Save());
- },
- HttpVerb::kPost);
-
- m_Router.RegisterRoute(
- "",
- [](HttpRouterRequest& Req) {
- CbObject Payload = Req.ServerRequest().ReadPayloadObject();
-
- CbObjectWriter Obj;
- Obj.AddBool("ok", true);
- Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Obj.Save());
- },
- HttpVerb::kPost);
-
-#if ZEN_WITH_TRACE
- m_Router.RegisterRoute(
- "trace",
- [this](HttpRouterRequest& Req) {
- bool Enabled = IsTracing();
- return Req.ServerRequest().WriteResponse(HttpResponseCode::OK, HttpContentType::kText, Enabled ? "enabled" : "disabled");
- },
- HttpVerb::kGet);
-
- m_Router.RegisterRoute(
- "trace/start",
- [this](HttpRouterRequest& Req) {
- HttpServerRequest& HttpReq = Req.ServerRequest();
- const HttpServerRequest::QueryParams Params = HttpReq.GetQueryParams();
- TraceOptions TraceOptions;
-
- if (!IsTracing())
- {
- TraceInit("zenserver");
- }
-
- if (auto Channels = Params.GetValue("channels"); Channels.empty() == false)
- {
- TraceOptions.Channels = Channels;
- }
-
- if (auto File = Params.GetValue("file"); File.empty() == false)
- {
- TraceOptions.File = File;
- }
- else if (auto Host = Params.GetValue("host"); Host.empty() == false)
- {
- TraceOptions.Host = Host;
- }
- else
- {
- return Req.ServerRequest().WriteResponse(HttpResponseCode::BadRequest,
- HttpContentType::kText,
- "Invalid trace type, use `file` or `host`"sv);
- }
-
- TraceConfigure(TraceOptions);
-
- return Req.ServerRequest().WriteResponse(HttpResponseCode::OK, HttpContentType::kText, "Tracing started");
- },
- HttpVerb::kPost);
-
- m_Router.RegisterRoute(
- "trace/stop",
- [this](HttpRouterRequest& Req) {
- if (!IsTracing())
- {
- return Req.ServerRequest().WriteResponse(HttpResponseCode::BadRequest, HttpContentType::kText, "Tracing is not enabled"sv);
- }
- if (TraceStop())
- {
- return Req.ServerRequest().WriteResponse(HttpResponseCode::OK, HttpContentType::kText, "Tracing stopped");
- }
- else
- {
- return Req.ServerRequest().WriteResponse(HttpResponseCode::InternalServerError,
- HttpContentType::kText,
- "Failed stopping trace");
- }
- },
- HttpVerb::kPost);
-#endif // ZEN_WITH_TRACE
-
- m_Router.RegisterRoute(
- "info",
- [this](HttpRouterRequest& Req) {
- CbObjectWriter Obj;
-
- Obj << "root" << m_ServerOptions.SystemRootDir.generic_wstring();
- Obj << "install" << (m_ServerOptions.SystemRootDir / "Install").generic_wstring();
-
- Obj.BeginObject("primary");
- Obj << "data" << m_ServerOptions.DataDir.generic_wstring();
-
- try
- {
- auto Stats = GetStatsForStateDirectory(m_ServerOptions.DataDir);
-
- auto EmitStats = [&](std::string_view Tag, const DirStats& Stats) {
- Obj.BeginObject(Tag);
- Obj << "bytes" << Stats.ByteCount;
- Obj << "files" << Stats.FileCount;
- Obj << "dirs" << Stats.DirCount;
- Obj.EndObject();
- };
-
- EmitStats("cache", Stats.CacheStats);
- EmitStats("cas", Stats.CasStats);
- EmitStats("project", Stats.ProjectStats);
- }
- catch (const std::exception& Ex)
- {
- ZEN_WARN("exception in disk stats gathering for '{}': {}", m_ServerOptions.DataDir, Ex.what());
- }
- Obj.EndObject();
-
- try
- {
- std::vector<CbObject> Manifests = ReadAllCentralManifests(m_ServerOptions.SystemRootDir);
-
- Obj.BeginArray("known");
-
- for (const auto& Manifest : Manifests)
- {
- Obj.AddObject(Manifest);
- }
-
- Obj.EndArray();
- }
- catch (const std::exception& Ex)
- {
- ZEN_WARN("exception in state gathering for '{}': {}", m_ServerOptions.SystemRootDir, Ex.what());
- }
- Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Obj.Save());
- },
- HttpVerb::kGet);
-
- m_Router.RegisterRoute(
- "logs",
- [this](HttpRouterRequest& Req) {
- CbObjectWriter Obj;
- auto LogLevel = logging::level::ToStringView(logging::GetLogLevel());
- Obj.AddString("loglevel", std::string_view(LogLevel.data(), LogLevel.size()));
- Obj.AddString("Logfile", PathToUtf8(m_LogPaths.AbsLogPath));
- Obj.BeginObject("cache");
- if (m_CacheStore)
- {
- const ZenCacheStore::Configuration& CacheConfig = m_CacheStore->GetConfiguration();
- Obj.AddString("Logfile", PathToUtf8(m_LogPaths.CacheLogPath));
- Obj.AddBool("Write", CacheConfig.Logging.EnableWriteLog);
- Obj.AddBool("Access", CacheConfig.Logging.EnableAccessLog);
- }
- Obj.EndObject();
- Obj.BeginObject("http");
- {
- Obj.AddString("Logfile", PathToUtf8(m_LogPaths.HttpLogPath));
- }
- Obj.EndObject();
- Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Obj.Save());
- },
- HttpVerb::kGet);
-
- m_Router.RegisterRoute(
- "logs",
- [this](HttpRouterRequest& Req) {
- HttpServerRequest& HttpReq = Req.ServerRequest();
- const HttpServerRequest::QueryParams Params = HttpReq.GetQueryParams();
- bool SetCacheLogConfig = false;
- ExtendableStringBuilder<256> StringBuilder;
- if (m_CacheStore)
- {
- ZenCacheStore::Configuration::LogConfig LoggingConfig = m_CacheStore->GetConfiguration().Logging;
- if (std::string Param(Params.GetValue("cacheenablewritelog")); Param.empty() == false)
- {
- LoggingConfig.EnableWriteLog = StrCaseCompare(Param.c_str(), "true") == 0;
- SetCacheLogConfig = true;
- }
- if (std::string Param(Params.GetValue("cacheenableaccesslog")); Param.empty() == false)
- {
- LoggingConfig.EnableAccessLog = StrCaseCompare(Param.c_str(), "true") == 0;
- SetCacheLogConfig = true;
- }
- if (SetCacheLogConfig)
- {
- m_CacheStore->SetLoggingConfig(LoggingConfig);
- StringBuilder.Append(fmt::format("cache write log: {}, cache access log: {}",
- LoggingConfig.EnableWriteLog ? "true" : "false",
- LoggingConfig.EnableAccessLog ? "true" : "false"));
- }
- }
- if (std::string Param(Params.GetValue("loglevel")); Param.empty() == false)
- {
- logging::level::LogLevel NewLevel = logging::level::ParseLogLevelString(Param);
- std::string_view LogLevel = logging::level::ToStringView(NewLevel);
- if (LogLevel != Param)
- {
- return Req.ServerRequest().WriteResponse(HttpResponseCode::BadRequest,
- HttpContentType::kText,
- fmt::format("Invalid log level '{}'", Param));
- }
- logging::SetLogLevel(NewLevel);
- if (StringBuilder.Size() > 0)
- {
- StringBuilder.Append(", ");
- }
- StringBuilder.Append("loglevel: ");
- StringBuilder.Append(Param);
- }
- return Req.ServerRequest().WriteResponse(HttpResponseCode::OK, HttpContentType::kText, StringBuilder.ToView());
- },
- HttpVerb::kPost);
- m_Router.RegisterRoute(
- "flush",
- [this](HttpRouterRequest& Req) {
- HttpServerRequest& HttpReq = Req.ServerRequest();
- m_FlushFunction();
- HttpReq.WriteResponse(HttpResponseCode::OK);
- },
- HttpVerb::kPost);
-}
-
-HttpAdminService::~HttpAdminService()
-{
-}
-
-const char*
-HttpAdminService::BaseUri() const
-{
- return "/admin/";
-}
-
-void
-HttpAdminService::HandleRequest(zen::HttpServerRequest& Request)
-{
- m_Router.HandleRequest(Request);
-}
-
-} // namespace zen