From 3d3f010656cf6c2274887bd5193531230dd7fbd3 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 27 Oct 2024 17:40:38 -0700 Subject: [PATCH 1/4] client: query the version of libc in WSL distros, and report it in scheduler requests. Note: the Linux client should report its libc version to the scheduler in a separate field, rather than encoding it in the OS version string --- client/hostinfo_wsl.cpp | 17 +++++++++++++++-- lib/util.cpp | 10 ++++++++++ lib/util.h | 7 +++++++ lib/wslinfo.cpp | 8 ++++++++ lib/wslinfo.h | 2 ++ 5 files changed, 42 insertions(+), 2 deletions(-) diff --git a/client/hostinfo_wsl.cpp b/client/hostinfo_wsl.cpp index 133d0ebaeea..ccaff2ddcbd 100644 --- a/client/hostinfo_wsl.cpp +++ b/client/hostinfo_wsl.cpp @@ -314,6 +314,15 @@ int get_wsl_information( // in case nothing worked update_os(wd, "unknown", "unknown"); + // get the libc version + if (!rs.run_program_in_wsl( + wd.distro_name, "ldd --version" + )) { + string buf; + read_from_pipe(rs.out_read, rs.proc_handle, buf, CMD_TIMEOUT); + wd.libc_version = parse_ldd_libc(buf); + } + // see if Docker is installed in the distro // if (detect_docker) { @@ -327,7 +336,9 @@ int get_wsl_information( return 0; } -static bool get_docker_version_aux(WSL_CMD &rs, WSL_DISTRO &wd, DOCKER_TYPE type) { +static bool get_docker_version_aux( + WSL_CMD &rs, WSL_DISTRO &wd, DOCKER_TYPE type +) { bool ret = false; string reply; string cmd = string(docker_cli_prog(type)) + " --version"; @@ -349,7 +360,9 @@ static void get_docker_version(WSL_CMD &rs, WSL_DISTRO &wd) { get_docker_version_aux(rs, wd, DOCKER); } -static bool get_docker_compose_version_aux(WSL_CMD &rs, WSL_DISTRO &wd, DOCKER_TYPE type) { +static bool get_docker_compose_version_aux( + WSL_CMD &rs, WSL_DISTRO &wd, DOCKER_TYPE type +) { bool ret = false; string reply; string cmd = string(docker_cli_prog(type)) + " compose version"; diff --git a/lib/util.cpp b/lib/util.cpp index c094f242fc2..7e4d8a8286e 100644 --- a/lib/util.cpp +++ b/lib/util.cpp @@ -685,3 +685,13 @@ bool process_exists(int pid) { } #endif + +string parse_ldd_libc(const char* input) { + const char *p = strrchr(input, ' '); + if (!p) return ""; + int maj, min; + if (sscanf(p, "%d.%d", &maj, &min) != 2) return ""; + string s = (string)p; + strip_whitespace(s); + return s; +} diff --git a/lib/util.h b/lib/util.h index 50edb8a680e..663856a2b71 100644 --- a/lib/util.h +++ b/lib/util.h @@ -130,6 +130,13 @@ extern int run_command(char *cmd, std::vector &out); // extern int get_real_executable_path(char* path, size_t max_len); +// given a string of the form +// ldd (Ubuntu GLIBC 2.27-3ubuntu1.6) 2.27 +// return "2.27" (or empty string if can't parse) +// + +extern std::string parse_ldd_libc(const char* input); + #ifdef GCL_SIMULATOR extern double simtime; #define time(x) ((int)simtime) diff --git a/lib/wslinfo.cpp b/lib/wslinfo.cpp index bcb1474b705..9298489a602 100644 --- a/lib/wslinfo.cpp +++ b/lib/wslinfo.cpp @@ -27,6 +27,7 @@ void WSL_DISTRO::clear() { distro_name = ""; os_name = ""; os_version = ""; + libc_version = ""; is_default = false; wsl_version = 1; docker_version = ""; @@ -51,6 +52,12 @@ void WSL_DISTRO::write_xml(MIOFILE& f) { is_default ? 1 : 0, wsl_version ); + if (!libc_version.empty()) { + f.printf( + " %s\n", + libc_version.c_str() + ); + } if (!docker_version.empty()) { f.printf( " %s\n" @@ -82,6 +89,7 @@ int WSL_DISTRO::parse(XML_PARSER& xp) { if (xp.parse_string("distro_name", distro_name)) continue; if (xp.parse_string("os_name", os_name)) continue; if (xp.parse_string("os_version", os_version)) continue; + if (xp.parse_string("libc_version", libc_version)) continue; if (xp.parse_bool("is_default", is_default)) continue; if (xp.parse_int("wsl_version", wsl_version)) continue; if (xp.parse_string("docker_version", docker_version)) continue; diff --git a/lib/wslinfo.h b/lib/wslinfo.h index 4677aa5be1c..18bc74d261c 100644 --- a/lib/wslinfo.h +++ b/lib/wslinfo.h @@ -37,6 +37,8 @@ struct WSL_DISTRO { // name of the operating system std::string os_version; // version of the operating system + std::string libc_version; + // version of libc, as reported by ldd --version int wsl_version; // version of WSL (currently 1 or 2) bool is_default; From dcb82a9b2ec60839df201560bc1c63ca10b93545 Mon Sep 17 00:00:00 2001 From: davidpanderson Date: Sun, 27 Oct 2024 18:27:04 -0700 Subject: [PATCH 2/4] fixes --- client/client_state.cpp | 5 +++++ client/hostinfo_wsl.cpp | 3 ++- lib/util.cpp | 2 ++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/client/client_state.cpp b/client/client_state.cpp index e1c356a57ce..9d9904792cd 100644 --- a/client/client_state.cpp +++ b/client/client_state.cpp @@ -262,6 +262,11 @@ void CLIENT_STATE::show_host_info() { "- OS: %s (%s)", wsl.os_name.c_str(), wsl.os_version.c_str() ); + if (!wsl.libc_version.empty()) { + msg_printf(NULL, MSG_INFO, + "- libc version: %s", wsl.libc_version.c_str() + ); + } if (!wsl.docker_version.empty()) { msg_printf(NULL, MSG_INFO, "- Docker version %s (%s)", wsl.docker_version.c_str(), diff --git a/client/hostinfo_wsl.cpp b/client/hostinfo_wsl.cpp index ccaff2ddcbd..7fc7b76e8b6 100644 --- a/client/hostinfo_wsl.cpp +++ b/client/hostinfo_wsl.cpp @@ -24,6 +24,7 @@ using std::string; #include "str_replace.h" #include "client_msgs.h" #include "hostinfo.h" +#include "util.h" // timeout for commands run in WSL container // If something goes wrong we don't want client to hang @@ -320,7 +321,7 @@ int get_wsl_information( )) { string buf; read_from_pipe(rs.out_read, rs.proc_handle, buf, CMD_TIMEOUT); - wd.libc_version = parse_ldd_libc(buf); + wd.libc_version = parse_ldd_libc(buf.c_str()); } // see if Docker is installed in the distro diff --git a/lib/util.cpp b/lib/util.cpp index 7e4d8a8286e..bff73fbaff6 100644 --- a/lib/util.cpp +++ b/lib/util.cpp @@ -687,6 +687,8 @@ bool process_exists(int pid) { #endif string parse_ldd_libc(const char* input) { + char *q = (char*)strchr(input, '\n'); + if (q) *q = 0; const char *p = strrchr(input, ' '); if (!p) return ""; int maj, min; From c11966b433c715c0ff495e694b8822a346c961e3 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 28 Oct 2024 13:02:30 -0700 Subject: [PATCH 3/4] Tweaks to WSL and Docker support - New philosophy: always query the presence of software (WSL distros, Docker) even if client config doesn't allow its use. Send the config info to scheduler, and enforce it there. - New philosophy: allow running jobs in any WSL distro except those disallowed in the config - Add plan class support for WSL and Docker app versions - client: query the libc version of WSL distros. The plan class entry for a WSL app version can specify a min libc version. - wsl_wrapper: add --min_libc_version cmdline arg (should match plan class spec) Notes: encoding version numbers into integers (e.g. 2.27 -> 227) was a bad idea. We should just store them as strings, and define a VERSION_NUM class for parsing and comparing them. Too late now, I guess --- client/hostinfo_win.cpp | 22 +++++------- client/hostinfo_wsl.cpp | 29 ++++++---------- client/log_flags.cpp | 16 ++++----- lib/cc_config.cpp | 12 +++---- lib/cc_config.h | 2 +- lib/wslinfo.cpp | 29 +++++++++++++--- lib/wslinfo.h | 6 +++- samples/wsl_wrapper/wsl_wrapper.cpp | 7 +++- sched/plan_class_spec.cpp | 54 ++++++++++++++++++++++++++++- sched/plan_class_spec.h | 2 ++ sched/sched_types.cpp | 2 ++ sched/sched_types.h | 4 +++ 12 files changed, 131 insertions(+), 54 deletions(-) diff --git a/client/hostinfo_win.cpp b/client/hostinfo_win.cpp index e17f8b9ed80..7f49b863066 100644 --- a/client/hostinfo_win.cpp +++ b/client/hostinfo_win.cpp @@ -1666,23 +1666,19 @@ int HOST_INFO::get_host_info(bool init) { os_name, sizeof(os_name), os_version, sizeof(os_version) ); #ifdef _WIN64 - if (!cc_config.dont_use_wsl) { - OSVERSIONINFOEX osvi; - if (get_OSVERSIONINFO(osvi) && osvi.dwMajorVersion >= 10) { - retval = get_wsl_information( - cc_config.allowed_wsls, wsl_distros, !cc_config.dont_use_docker + OSVERSIONINFOEX osvi; + if (get_OSVERSIONINFO(osvi) && osvi.dwMajorVersion >= 10) { + retval = get_wsl_information(wsl_distros); + if (retval) { + msg_printf(0, MSG_INTERNAL_ERROR, + "get_wsl_information(): %s", boincerror(retval) ); - if (retval) { - msg_printf(0, MSG_INTERNAL_ERROR, - "get_wsl_information(): %s", boincerror(retval) - ); - } } } #endif - if (!cc_config.dont_use_vbox) { - get_virtualbox_version(); - } + + get_virtualbox_version(); + get_processor_info( p_vendor, sizeof(p_vendor), p_model, sizeof(p_model), diff --git a/client/hostinfo_wsl.cpp b/client/hostinfo_wsl.cpp index 7fc7b76e8b6..a64f5481d14 100644 --- a/client/hostinfo_wsl.cpp +++ b/client/hostinfo_wsl.cpp @@ -170,17 +170,12 @@ static bool got_both(WSL_DISTRO &wd) { } // Get list of WSL distros usable by BOINC -// (docker_desktop and those allowed by config) // For each of them: // try to find the OS name and version // see if Docker and docker compose are present, get versions // Return nonzero on error // -int get_wsl_information( - vector &allowed_wsls, - WSL_DISTROS &usable_distros, - bool detect_docker // whether to check for Docker -) { +int get_wsl_information(WSL_DISTROS &distros) { WSL_DISTROS all_distros; int retval = get_all_distros(all_distros); if (retval) return retval; @@ -200,14 +195,6 @@ int get_wsl_information( if (wd.distro_name == "docker-desktop-data"){ continue; } - // skip distros that are not allowed except for 'docker-desktop' - // - if (wd.distro_name != "docker-desktop" - && std::find(allowed_wsls.begin(), allowed_wsls.end(), wd.distro_name) == allowed_wsls.end() - ) { - msg_printf(0, MSG_INFO, "WSL distro '%s' detected but is not allowed", wd.distro_name.c_str()); - continue; - } char os_name[256]; char os_version[256]; @@ -326,12 +313,16 @@ int get_wsl_information( // see if Docker is installed in the distro // - if (detect_docker) { - get_docker_version(rs, wd); - get_docker_compose_version(rs, wd); - } + get_docker_version(rs, wd); + get_docker_compose_version(rs, wd); - usable_distros.distros.push_back(wd); + // see if distro is disallowed + // + vector &dw = cc_config.disallowed_wsls; + if (std::find(dw.begin(), dw.end(), wd.distro_name,) != dw.end()) { + dw.disallowed = true; + } + distros.distros.push_back(wd); } return 0; diff --git a/client/log_flags.cpp b/client/log_flags.cpp index 86d2db0920d..74c11ca5253 100644 --- a/client/log_flags.cpp +++ b/client/log_flags.cpp @@ -195,17 +195,17 @@ void CC_CONFIG::show() { if (dont_use_vbox) { msg_printf(NULL, MSG_INFO, "Config: don't use VirtualBox"); } + if (dont_use_docker) { + msg_printf(NULL, MSG_INFO, "Config: don't use Docker"); + } if (dont_use_wsl) { - msg_printf(NULL, MSG_INFO, "Config: don't use the Windows Subsystem for Linux"); + msg_printf(NULL, MSG_INFO, "Config: don't use Windows Subsystem for Linux"); } - for (string s: allowed_wsls) { + for (string s: disallowed_wsls) { msg_printf(NULL, MSG_INFO, - "Config: allowed WSL distro: %s", s.c_str() + "Config: disallowed WSL distro: %s", s.c_str() ); } - if (dont_use_docker) { - msg_printf(NULL, MSG_INFO, "Config: don't use the Docker"); - } for (i=0; i%s\n", - allowed_wsls[i].c_str() + " %s\n", + disallowed_wsls[i].c_str() ); } diff --git a/lib/cc_config.h b/lib/cc_config.h index 620850df5a4..a2c0ba5bb90 100644 --- a/lib/cc_config.h +++ b/lib/cc_config.h @@ -167,7 +167,7 @@ struct CC_CONFIG { bool dont_suspend_nci; bool dont_use_vbox; bool dont_use_wsl; - std::vector allowed_wsls; + std::vector disallowed_wsls; bool dont_use_docker; std::vector exclude_gpus; std::vector exclusive_apps; diff --git a/lib/wslinfo.cpp b/lib/wslinfo.cpp index 9298489a602..86805ebd48a 100644 --- a/lib/wslinfo.cpp +++ b/lib/wslinfo.cpp @@ -28,8 +28,9 @@ void WSL_DISTRO::clear() { os_name = ""; os_version = ""; libc_version = ""; + disallowed = false; is_default = false; - wsl_version = 1; + wsl_version = 0; docker_version = ""; docker_compose_version = ""; } @@ -44,14 +45,22 @@ void WSL_DISTRO::write_xml(MIOFILE& f) { " %s\n" " %s\n" " %s\n" - " %d\n" " %d\n", dn, n, v, - is_default ? 1 : 0, wsl_version ); + if (is_default) { + f.printf( + " \n" + ); + } + if (disallowed) { + f.printf( + " \n" + ); + } if (!libc_version.empty()) { f.printf( " %s\n", @@ -91,6 +100,7 @@ int WSL_DISTRO::parse(XML_PARSER& xp) { if (xp.parse_string("os_version", os_version)) continue; if (xp.parse_string("libc_version", libc_version)) continue; if (xp.parse_bool("is_default", is_default)) continue; + if (xp.parse_bool("disallowed", disallowed)) continue; if (xp.parse_int("wsl_version", wsl_version)) continue; if (xp.parse_string("docker_version", docker_version)) continue; if (xp.parse_int("docker_type", i)) { @@ -106,6 +116,13 @@ int WSL_DISTRO::parse(XML_PARSER& xp) { return ERR_XML_PARSE; } +int WSL_DISTRO::libc_version_int() { + int maj, min; + int n = sscanf(libc_version.c_str(), "%d.%d", &maj, &min); + if (n==2) return maj*100+min; + return 0; +} + WSL_DISTROS::WSL_DISTROS() { clear(); } @@ -139,7 +156,8 @@ int WSL_DISTROS::parse(XML_PARSER& xp) { } WSL_DISTRO* WSL_DISTROS::find_match( - const char *os_name_regexp, const char *os_version_regexp + const char *os_name_regexp, const char *os_version_regexp, + int min_libc_version ) { std::regex name_regex(os_name_regexp), version_regex(os_version_regexp); for (WSL_DISTRO &wd: distros) { @@ -149,6 +167,9 @@ WSL_DISTRO* WSL_DISTROS::find_match( if (!std::regex_match(wd.os_version.c_str(), version_regex)) { continue; } + if (wd.libc_version_int() < min_libc_version) { + continue; + } return &wd; } return NULL; diff --git a/lib/wslinfo.h b/lib/wslinfo.h index 18bc74d261c..4b6e239d821 100644 --- a/lib/wslinfo.h +++ b/lib/wslinfo.h @@ -43,6 +43,8 @@ struct WSL_DISTRO { // version of WSL (currently 1 or 2) bool is_default; // this is the default distro + bool disallowed; + // disallowed in cc_config.xml std::string docker_version; // version of Docker (or podman) // empty if not present @@ -57,6 +59,7 @@ struct WSL_DISTRO { void clear(); void write_xml(MIOFILE&); int parse(XML_PARSER&); + int libc_version_int(); }; // a set of WSL distros @@ -69,7 +72,8 @@ struct WSL_DISTROS { void write_xml(MIOFILE&); int parse(XML_PARSER&); WSL_DISTRO *find_match( - const char *os_name_regexp, const char *os_version_regexp + const char *os_name_regexp, const char *os_version_regexp, + int min_libc_version ); WSL_DISTRO *find_docker(); // find a distro containing Docker diff --git a/samples/wsl_wrapper/wsl_wrapper.cpp b/samples/wsl_wrapper/wsl_wrapper.cpp index 09dc795849c..0272024441a 100644 --- a/samples/wsl_wrapper/wsl_wrapper.cpp +++ b/samples/wsl_wrapper/wsl_wrapper.cpp @@ -214,6 +214,7 @@ void poll_client_msgs() { int main(int argc, char** argv) { const char *os_name_regexp=".*", *os_version_regexp=".*", *pass_thru=""; + int min_libc_version = 0; for (int i=1; i\n"); char buf[BLOB_SIZE]; diff --git a/sched/sched_types.h b/sched/sched_types.h index cac8aa3f7a3..71795bb98f2 100644 --- a/sched/sched_types.h +++ b/sched/sched_types.h @@ -267,6 +267,9 @@ struct PLATFORM_LIST { std::vector list; }; +// if you add anything: +// - add it to clear() +// - add it to parse() struct SCHEDULER_REQUEST { char authenticator[256]; CLIENT_PLATFORM platform; @@ -339,6 +342,7 @@ struct SCHEDULER_REQUEST { // whether client uses account-based sandbox. -1 = don't know int allow_multiple_clients; // whether client allows multiple clients per host, -1 don't know + bool dont_use_wsl; bool dont_use_docker; bool using_weak_auth; // Request uses weak authenticator. From 63ef5f1660ef50748b08f5aee59a406ffd05d961 Mon Sep 17 00:00:00 2001 From: davidpanderson Date: Mon, 28 Oct 2024 13:24:52 -0700 Subject: [PATCH 4/4] Win compile fixes --- client/hostinfo_wsl.cpp | 4 ++-- lib/hostinfo.h | 6 +----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/client/hostinfo_wsl.cpp b/client/hostinfo_wsl.cpp index a64f5481d14..cb852c4ab79 100644 --- a/client/hostinfo_wsl.cpp +++ b/client/hostinfo_wsl.cpp @@ -319,8 +319,8 @@ int get_wsl_information(WSL_DISTROS &distros) { // see if distro is disallowed // vector &dw = cc_config.disallowed_wsls; - if (std::find(dw.begin(), dw.end(), wd.distro_name,) != dw.end()) { - dw.disallowed = true; + if (std::find(dw.begin(), dw.end(), wd.distro_name) != dw.end()) { + wd.disallowed = true; } distros.distros.push_back(wd); } diff --git a/lib/hostinfo.h b/lib/hostinfo.h index bf58cb9fbba..c365379c090 100644 --- a/lib/hostinfo.h +++ b/lib/hostinfo.h @@ -173,11 +173,7 @@ class HOST_INFO { extern void make_secure_random_string(char*); #ifdef _WIN64 -extern int get_wsl_information( - std::vector &allowed_wsls, - WSL_DISTROS &usable_distros, - bool detect_docker -); +extern int get_wsl_information(WSL_DISTROS &distros); extern int get_processor_group(HANDLE); #endif