From 2d9c3cab76255e7545105f21b5c0ab618b0f7734 Mon Sep 17 00:00:00 2001 From: chn Date: Wed, 1 May 2024 10:45:25 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E7=99=BB=E9=99=86=E7=99=BB?= =?UTF-8?q?=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .clangd | 2 +- CMakeLists.txt | 5 +- flake.nix | 2 +- src/main.cpp | 158 ++++++++++++++++++++++++++----------------------- 4 files changed, 86 insertions(+), 81 deletions(-) diff --git a/.clangd b/.clangd index e80b999..a6585d7 100644 --- a/.clangd +++ b/.clangd @@ -1,3 +1,3 @@ CompileFlags: Add: [ -Wall, -Wextra, -std=c++23 ] - Compiler: gcc + Compiler: g++ diff --git a/CMakeLists.txt b/CMakeLists.txt index aa1442f..4994c52 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,10 +3,6 @@ project(hpcstat VERSION 0.0.0 LANGUAGES CXX) enable_testing() include(GNUInstallDirs) -set_property(GLOBAL PROPERTY CXX_STANDARD 23) -set_property(GLOBAL PROPERTY CXX_STANDARD_REQUIRED ON) -set_property(GLOBAL PROPERTY CXX_EXTENSIONS OFF) - if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) message("Setting build type to 'Release' as none was specified.") set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE) @@ -18,6 +14,7 @@ find_package(Boost REQUIRED COMPONENTS headers filesystem) find_package(zxorm REQUIRED) add_executable(hpcstat src/main.cpp) +target_compile_features(hpcstat PUBLIC cxx_std_23) target_link_libraries(hpcstat PRIVATE fmt::fmt Boost::headers Boost::filesystem zxorm::zxorm) install(TARGETS hpcstat RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/flake.nix b/flake.nix index eb389c6..f66e041 100644 --- a/flake.nix +++ b/flake.nix @@ -22,7 +22,7 @@ { name = "hpcstat"; src = ./.; - buildInputs = with pkgs.pkgsStatic; [ boost fmt sqlitecpp ]; + buildInputs = with pkgs.pkgsStatic; [ boost fmt localPackages.zxorm ]; nativeBuildInputs = with pkgs; [ cmake pkg-config ]; postInstall = "cp ${openssh}/bin/ssh-add $out/bin"; }; diff --git a/src/main.cpp b/src/main.cpp index 272826a..4a0c85d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -18,18 +18,27 @@ using namespace std::literals; // ssh fingerprint -> username const std::map Username { - { "LNoYfq/SM7l8sFAy325WpC+li+kZl3jwST7TmP72Tz8", "Haonan Chen" } + { "LNoYfq/SM7l8sFAy325WpC+li+kZl3jwST7TmP72Tz8", "Haonan Chen" }, + { "VJT5wgkb2RcIeVNTA+/NKxokctbYnJ/KgH6IxrKqIGE", "Bin Gong" }, + { "umC3/RB1vS8TQBHsY3IzhOiyqVrOSw2fB3rIpDQSmf4", "Leilei Xiang" }, + { "fdq5k13N2DAzIK/2a1Mm4/ZVsDUgT623TSOXsVswxT8", "Junqi Yao" }, + { "8USxEYi8ePPpLhk5FYBo2udT7/NFmEe8c2+oQajGXzA", "Enming Zhang" }, + { "7bmG24muNsaAZkCy7mQ9Nf2HuNafmvUO+Hf1bId9zts", "Yaping Wu" }, + { "dtx0QxdgFrXn2SYxtIRz43jIAH6rLgJidSdTvuTuews", "Jing Li" }, + { "8crUO9u4JiVqw3COyjXfzZe87s6XZFhvi0LaY0Mv6bg", "Huahan Zhan" }, + { "QkmIYw7rmDEAP+LDWxm6L2/XLnAqTwRUB7B0pxYlOUs", "Na Gao" } }; // program path, set at start of main, e.g. /gpfs01/.../bin/hpcstat std::filesystem::path Program; -// run a program, wait until it exit, return its stdout and stderr if it return 0, otherwise nullopt +// run a program, wait until it exit, return its stdout if it return 0, otherwise nullopt std::optional exec(boost::filesystem::path program, std::vector args) { namespace bp = boost::process; bp::ipstream output; - auto process = bp::child(program, bp::args(args), bp::std_out > output, bp::std_err > bp::null); + auto process = bp::child + (program, bp::args(args), bp::std_out > output, bp::std_err > stderr, bp::std_in < bp::null); process.wait(); if (process.exit_code() != 0) return std::nullopt; std::stringstream ss; @@ -38,11 +47,12 @@ std::optional exec(boost::filesystem::path program, std::vector> fingerprints() { auto output = exec(Program.replace_filename("ssh-add"), { "-l" }); - if (!output) return std::nullopt; + if (!output) { std::cerr << "Failed to get ssh fingerprints\n"; return std::nullopt; } auto fingerprint = output->substr(0, 47); // search for all strings that match the fingerprint pattern: sha256:... std::regex pattern(R"r(\b(?:sha|SHA)256:([0-9A-Za-z+/=]{43})\b)r"); @@ -60,17 +70,16 @@ std::optional> authenticated() if (!fps) return std::nullopt; for (auto& fp : *fps) if (Username.contains(fp)) return std::make_pair(fp, Username.at(fp)); + std::cerr << fmt::format("No valid fingerprint found, available fingerprints: {}\n", *fps); return std::nullopt; } // initialize the database -// std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); struct LoginData { - unsigned Id = 0; - long Time = 0; - std::string Key; - std::string SessionId; + unsigned Id = 0; long Time = 0; + std::string Key, SessionId; + std::optional Subaccount; bool Interactive; }; using LoginTable = zxorm::Table @@ -79,115 +88,114 @@ using LoginTable = zxorm::Table zxorm::Column<"id", &LoginData::Id, zxorm::PrimaryKey<>>, zxorm::Column<"time", &LoginData::Time>, zxorm::Column<"key", &LoginData::Key>, - zxorm::Column<"session_id", &LoginData::SessionId> + zxorm::Column<"session_id", &LoginData::SessionId>, + zxorm::Column<"sub_account", &LoginData::Subaccount>, + zxorm::Column<"interactive", &LoginData::Interactive> >; -struct LogoutData -{ - unsigned Id = 0; - long Time = 0; - std::string SessionId; -}; +struct LogoutData { unsigned Id = 0; long Time = 0; std::string SessionId; }; using LogoutTable = zxorm::Table < "logout", LogoutData, zxorm::Column<"id", &LogoutData::Id, zxorm::PrimaryKey<>>, - zxorm::Column<"time", &LogoutData::Time>, - zxorm::Column<"session_id", &LogoutData::SessionId> + zxorm::Column<"time", &LogoutData::Time>, zxorm::Column<"sessionid", &LogoutData::SessionId> +>; +struct SubmitJobData + { unsigned Id = 0; long Time = 0; int JobId; std::string Key, SessionId, Subaccount, SubmitDir, JobCommand; }; +using SubmitJobTable = zxorm::Table +< + "submitjob", SubmitJobData, + zxorm::Column<"id", &SubmitJobData::Id, zxorm::PrimaryKey<>>, + zxorm::Column<"time", &SubmitJobData::Time>, + zxorm::Column<"job_id", &SubmitJobData::JobId>, + zxorm::Column<"key", &SubmitJobData::Key>, + zxorm::Column<"session_id", &SubmitJobData::SessionId>, + zxorm::Column<"sub_account", &SubmitJobData::Subaccount>, + zxorm::Column<"submit_dir", &SubmitJobData::SubmitDir>, + zxorm::Column<"job_command", &SubmitJobData::JobCommand> +>; +struct FinishJobData { unsigned Id = 0; long Time = 0; int JobId; std::string JobResult; double CpuTime; }; +using FinishJobTable = zxorm::Table +< + "finishjob", FinishJobData, + zxorm::Column<"id", &FinishJobData::Id, zxorm::PrimaryKey<>>, + zxorm::Column<"time", &FinishJobData::Time>, + zxorm::Column<"job_id", &FinishJobData::JobId>, + zxorm::Column<"job_result", &FinishJobData::JobResult>, + zxorm::Column<"cpu_time", &FinishJobData::CpuTime> +>; +struct QueryJobData { unsigned Id = 0; int JobId; }; +using QueryJobTable = zxorm::Table +< + "queryjob", QueryJobData, + zxorm::Column<"id", &QueryJobData::Id, zxorm::PrimaryKey<>>, zxorm::Column<"job_id", &QueryJobData::JobId> >; -// struct SubmitData -// { -// unsigned Id; -// long Time; -// std::string Key; -// std::string SessionId; -// unsigned JobId; -// std::string JobWorkdir; -// std::string JobCommand; -// }; -// struct FinishData -// { -// unsigned Id; -// long Time; -// unsigned JobId; -// std::string JobResult; -// double CpuTime; -// }; void initdb() { auto dbfile = Program.replace_filename("hpcstat.db").string(); - zxorm::Connection conn(dbfile.c_str()); + zxorm::Connection + conn(dbfile.c_str()); conn.create_tables(); } void writedb(auto value) { auto dbfile = Program.replace_filename("hpcstat.db").string(); - zxorm::Connection conn(dbfile.c_str()); + zxorm::Connection + conn(dbfile.c_str()); value.Time = std::chrono::duration_cast (std::chrono::system_clock::now().time_since_epoch()).count(); conn.insert_record(value); } -bool interactive() -{ - return isatty(fileno(stdin)); -} +bool interactive() { return isatty(fileno(stdin)); } // get value of XDG_SESSION_ID std::optional session_id() { - auto value = std::getenv("XDG_SESSION_ID"); - if (!value) return std::nullopt; else return value; + if (auto value = std::getenv("XDG_SESSION_ID"); !value) + { std::cerr << "Failed to get session id\n"; return std::nullopt; } + else return value; } +// get value of HPCSTAT_SUBACCOUNT +std::optional subaccount() + { if (auto value = std::getenv("HPCSTAT_SUBACCOUNT"); value) return value; else return std::nullopt; } + int main(int argc, const char** argv) { std::vector args(argv, argv + argc); Program = args[0]; - if (args.size() == 1) - { - std::cout << "Usage: hpcstat initdb|login|logout|submitjob|finishjob\n"; - return 1; - } + if (args.size() == 1) { std::cout << "Usage: hpcstat initdb|login|logout|submitjob|finishjob\n"; return 1; } else if (args[1] == "initdb") initdb(); else if (args[1] == "login") { - auto key = authenticated(); - if (!key) - { - auto fps = fingerprints(); - if (!fingerprints()) - std::cerr << "Failed to get ssh fingerprints\n"; - else - std::cerr << fmt::format("No valid fingerprint found, available fingerprints: {}\n", *fps); - return 1; - } - auto session = session_id(); - if (!session) - { - std::cerr << "Failed to get session id\n"; - return 1; - } - writedb(LoginData{.Key = key->first, .SessionId = *session, .Interactive = interactive()}); + if (auto key = authenticated(); !key) return 1; + else if (auto session = session_id(); !session) return 1; + else writedb(LoginData + {.Key = key->first, .SessionId = *session, .Subaccount = subaccount(), .Interactive = interactive()}); } else if (args[1] == "logout") { - auto session = session_id(); - if (!session) - { - std::cerr << "Failed to get session id\n"; - return 1; - } - writedb(LogoutData{.SessionId = *session}); + if (auto session = session_id(); !session) return 1; + else writedb(LogoutData{.SessionId = *session}); } else if (args[1] == "submitjob") { - // TODO + if (args.size() < 4) { std::cerr << "Usage: hpcstat submitjob \n"; return 1; } + if (auto key = authenticated(); !key) return 1; + else if (auto session = session_id(); !session) return 1; + else writedb(SubmitJobData + { + .JobId = std::stoi(args[2]), .Key = key->first, .SessionId = *session, + .SubmitDir = std::filesystem::current_path().string(), + .JobCommand = [&] + { std::stringstream ss; for (int i = 3; i < args.size(); i++) ss << args[i] << " "; return ss.str(); }() + }); } else if (args[1] == "finishjob") { - // TODO + } else {