From c7d4dc6a4d13881028d566f5ce501335e47e48bf Mon Sep 17 00:00:00 2001 From: Dan Engelbrecht Date: Fri, 22 Sep 2023 08:22:06 -0400 Subject: Collect all zen admin-related commands into admin.h/.cpp (#418) * move commands in scrub.h/cpp to admin_cmd.h/cpp * move job command into admin_cmd.h/.cpp * admin -> admin_cmd * bench -> bench_cmd * cache -> cache_cmd * copy -> copy_cmd * dedup -> dedup_cmd * hash -> hash_cmd * print -> print_cmd * projectstore -> projectstore_cmd * rpcreplay -> rpcreplay_cmd * serve -> serve_cmd * status -> status_cmd * top -> top_cmd * trace -> trace_cmd * up -> up_cmd * version -> version_cmd --- src/zen/cmds/admin_cmd.cpp | 270 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 270 insertions(+) create mode 100644 src/zen/cmds/admin_cmd.cpp (limited to 'src/zen/cmds/admin_cmd.cpp') diff --git a/src/zen/cmds/admin_cmd.cpp b/src/zen/cmds/admin_cmd.cpp new file mode 100644 index 000000000..0aef968a9 --- /dev/null +++ b/src/zen/cmds/admin_cmd.cpp @@ -0,0 +1,270 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "admin_cmd.h" +#include +#include +#include +#include + +ZEN_THIRD_PARTY_INCLUDES_START +#include +ZEN_THIRD_PARTY_INCLUDES_END + +using namespace std::literals; + +namespace zen { + +ScrubCommand::ScrubCommand() +{ + m_Options.add_options()("h,help", "Print help"); + m_Options.add_option("", "u", "hosturl", "Host URL", cxxopts::value(m_HostName)->default_value(""), ""); +} + +ScrubCommand::~ScrubCommand() = default; + +int +ScrubCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) +{ + ZEN_UNUSED(GlobalOptions); + + if (!ParseOptions(argc, argv)) + { + return 0; + } + + m_HostName = ResolveTargetHostSpec(m_HostName); + + if (m_HostName.empty()) + { + throw OptionParseException("unable to resolve server specification"); + } + + zen::HttpClient Http(m_HostName); + + if (zen::HttpClient::Response Response = Http.Post("/admin/scrub"sv)) + { + ZEN_CONSOLE("OK: {}", Response.ToText()); + + return 0; + } + else if (int StatusCode = (int)Response.StatusCode) + { + ZEN_ERROR("scrub start failed: {}: {} ({})", + (int)Response.StatusCode, + ReasonStringForHttpResultCode((int)Response.StatusCode), + Response.AsText()); + } + else + { + ZEN_ERROR("scrub start failed: {}", Response.AsText()); + } + + return 1; +} + +////////////////////////////////////////////////////////////////////////// + +GcCommand::GcCommand() +{ + m_Options.add_options()("h,help", "Print help"); + m_Options.add_option("", "u", "hosturl", "Host URL", cxxopts::value(m_HostName)->default_value(""), ""); + m_Options.add_option("", + "s", + "smallobjects", + "Collect small objects", + cxxopts::value(m_SmallObjects)->default_value("false"), + ""); + m_Options.add_option("", + "m", + "maxcacheduration", + "Max cache lifetime (in seconds)", + cxxopts::value(m_MaxCacheDuration)->default_value("0"), + ""); + m_Options.add_option("", + "d", + "disksizesoftlimit", + "Max disk usage size (in bytes)", + cxxopts::value(m_DiskSizeSoftLimit)->default_value("0"), + ""); +} + +GcCommand::~GcCommand() +{ +} + +int +GcCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) +{ + ZEN_UNUSED(GlobalOptions); + + if (!ParseOptions(argc, argv)) + { + return 0; + } + + m_HostName = ResolveTargetHostSpec(m_HostName); + + if (m_HostName.empty()) + { + throw OptionParseException("unable to resolve server specification"); + } + + cpr::Parameters Params; + if (m_SmallObjects) + { + Params.Add({"smallobjects", "true"}); + } + if (m_MaxCacheDuration != 0) + { + Params.Add({"maxcacheduration", fmt::format("{}", m_MaxCacheDuration)}); + } + if (m_DiskSizeSoftLimit != 0) + { + Params.Add({"disksizesoftlimit", fmt::format("{}", m_DiskSizeSoftLimit)}); + } + + cpr::Session Session; + Session.SetHeader(cpr::Header{{"Accept", "application/json"}}); + Session.SetUrl({fmt::format("{}/admin/gc", m_HostName)}); + Session.SetParameters(Params); + + cpr::Response Result = Session.Post(); + + if (zen::IsHttpSuccessCode(Result.status_code)) + { + ZEN_CONSOLE("OK: {}", Result.text); + return 0; + } + + if (Result.status_code) + { + ZEN_ERROR("GC start failed: {}: {} ({})", Result.status_code, Result.reason, Result.text); + } + else + { + ZEN_ERROR("GC start failed: {}", Result.error.message); + } + + return 1; +} + +GcStatusCommand::GcStatusCommand() +{ + m_Options.add_options()("h,help", "Print help"); + m_Options.add_option("", "u", "hosturl", "Host URL", cxxopts::value(m_HostName)->default_value(""), ""); +} + +GcStatusCommand::~GcStatusCommand() +{ +} + +int +GcStatusCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) +{ + ZEN_UNUSED(GlobalOptions); + + if (!ParseOptions(argc, argv)) + { + return 0; + } + + m_HostName = ResolveTargetHostSpec(m_HostName); + + if (m_HostName.empty()) + { + throw OptionParseException("unable to resolve server specification"); + } + + cpr::Session Session; + Session.SetHeader(cpr::Header{{"Accept", "application/json"}}); + Session.SetUrl({fmt::format("{}/admin/gc", m_HostName)}); + + cpr::Response Result = Session.Get(); + + if (zen::IsHttpSuccessCode(Result.status_code)) + { + ZEN_CONSOLE("OK: {}", Result.text); + return 0; + } + + if (Result.status_code) + { + ZEN_ERROR("GC status failed: {}: {} ({})", Result.status_code, Result.reason, Result.text); + } + else + { + ZEN_ERROR("GC status failed: {}", Result.error.message); + } + + return 1; +} + +//////////////////////////////////////////// + +JobCommand::JobCommand() +{ + m_Options.add_options()("h,help", "Print help"); + m_Options.add_option("", "u", "hosturl", "Host URL", cxxopts::value(m_HostName)->default_value(""), ""); + m_Options.add_option("", "j", "jobid", "Job id", cxxopts::value(m_JobId), ""); + m_Options.add_option("", "c", "cancel", "Cancel job id", cxxopts::value(m_Cancel), ""); +} + +JobCommand::~JobCommand() = default; + +int +JobCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) +{ + ZEN_UNUSED(GlobalOptions); + + using namespace std::literals; + + if (!ParseOptions(argc, argv)) + { + return 0; + } + + m_HostName = ResolveTargetHostSpec(m_HostName); + + if (m_HostName.empty()) + { + throw OptionParseException("unable to resolve server specification"); + } + + HttpClient Http(m_HostName); + + if (m_Cancel) + { + if (m_JobId == 0) + { + ZEN_ERROR("Job id must be given"); + return 1; + } + } + std::string Url = m_JobId != 0 ? fmt::format("/admin/jobs/{}", m_JobId) : "/admin/jobs"; + + if (m_Cancel) + { + if (HttpClient::Response Result = Http.Delete(Url, HttpClient::Accept(ZenContentType::kJSON))) + { + ZEN_CONSOLE("{}", Result); + } + else + { + Result.ThrowError("failed cancelling job"sv); + return 1; + } + } + else if (HttpClient::Response Result = Http.Get(Url, HttpClient::Accept(ZenContentType::kJSON))) + { + ZEN_CONSOLE("{}", Result.AsText()); + } + else + { + Result.ThrowError("failed fetching job info"sv); + return 1; + } + + return 0; +} + +} // namespace zen -- cgit v1.2.3 From 47ba787e2cfe32b252b74e09494fbcaabc4e8190 Mon Sep 17 00:00:00 2001 From: Dan Engelbrecht Date: Fri, 22 Sep 2023 10:04:02 -0400 Subject: Add runtime status/control of logging (#419) - Feature: New endpoint `/admin/logs` to query status of logging and log file locations and cache logging - `enablewritelog`=`true`/`false` parameter to control cache write logging - `enableaccesslog`=`true`/`false` parameter to control cache access logging - `loglevel` = `trace`/`debug`/`info`/`warning`/`error` - Feature: New zen command `logs` to query/control zen logging - No arguments gives status of logging and paths to log files - `--cache-write-log` `enable`/`disable` to control cache write logging - `--cache-access-log` `enable`/`disable` to control cache access logging - `--loglevel` `trace`/`debug`/`info`/`warning`/`error` to set debug level --- src/zen/cmds/admin_cmd.cpp | 102 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) (limited to 'src/zen/cmds/admin_cmd.cpp') diff --git a/src/zen/cmds/admin_cmd.cpp b/src/zen/cmds/admin_cmd.cpp index 0aef968a9..b48207bec 100644 --- a/src/zen/cmds/admin_cmd.cpp +++ b/src/zen/cmds/admin_cmd.cpp @@ -267,4 +267,106 @@ JobCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) return 0; } +//////////////////////////////////////////// + +LoggingCommand::LoggingCommand() +{ + m_Options.add_options()("h,help", "Print help"); + m_Options.add_option("", "u", "hosturl", "Host URL", cxxopts::value(m_HostName)->default_value(""), ""); + m_Options.add_option("", "", "cache-write-log", "Enable cache write logging", cxxopts::value(m_CacheWriteLog), ""); + m_Options.add_option("", "", "cache-access-log", "Enable cache access logging", cxxopts::value(m_CacheAccessLog), ""); + m_Options + .add_option("", "", "set-log-level", "Set zenserver log level", cxxopts::value(m_SetLogLevel), ""); +} + +LoggingCommand::~LoggingCommand() = default; + +int +LoggingCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) +{ + ZEN_UNUSED(GlobalOptions); + + using namespace std::literals; + + if (!ParseOptions(argc, argv)) + { + return 0; + } + + m_HostName = ResolveTargetHostSpec(m_HostName); + + if (m_HostName.empty()) + { + throw OptionParseException("unable to resolve server specification"); + } + + HttpClient Http(m_HostName); + + HttpClient::KeyValueMap Parameters; + + if (!m_CacheWriteLog.empty()) + { + if (m_CacheWriteLog == "enable") + { + (*Parameters)["cacheenablewritelog"] = "true"; + } + else if (m_CacheWriteLog == "disable") + { + (*Parameters)["cacheenablewritelog"] = "false"; + } + else + { + ZEN_ERROR("Invalid value for parameter 'cache-write-log'. Use 'enable' or 'disable'"); + return 1; + } + } + + if (!m_CacheAccessLog.empty()) + { + if (m_CacheAccessLog == "enable") + { + (*Parameters)["cacheenableaccesslog"] = "true"; + } + else if (m_CacheAccessLog == "disable") + { + (*Parameters)["cacheenableaccesslog"] = "false"; + } + else + { + ZEN_ERROR("Invalid value for parameter 'cache-access-log'. Use 'enable' or 'disable'"); + return 1; + } + } + + if (!m_SetLogLevel.empty()) + { + (*Parameters)["loglevel"] = m_SetLogLevel; + } + + if ((*Parameters).empty()) + { + if (HttpClient::Response Result = Http.Get("/admin/logs", HttpClient::Accept(ZenContentType::kJSON))) + { + ZEN_CONSOLE("{}", Result.AsText()); + } + else + { + Result.ThrowError("failed fetching log info"sv); + return 1; + } + return 0; + } + if (HttpClient::Response Result = Http.Post("/admin/logs", HttpClient::KeyValueMap{}, Parameters)) + { + ZEN_CONSOLE("{}", Result.AsText()); + } + else + { + Result.ThrowError("failed setting log info"sv); + return 1; + } + + return 0; +} + } // namespace zen -- cgit v1.2.3