diff --git a/client/client_state.cpp b/client/client_state.cpp index 7a1c9fcdb57..793642d40b9 100644 --- a/client/client_state.cpp +++ b/client/client_state.cpp @@ -248,7 +248,7 @@ void CLIENT_STATE::show_host_info() { #ifdef _WIN64 if (host_info.wsl_available) { - msg_printf(NULL, MSG_INFO, "WSL detected:"); + msg_printf(NULL, MSG_INFO, "WSL present:"); for (size_t i = 0; i < host_info.wsls.wsls.size(); ++i) { const WSL& wsl = host_info.wsls.wsls[i]; if (wsl.is_default) { @@ -262,7 +262,7 @@ void CLIENT_STATE::show_host_info() { } } } else { - msg_printf(NULL, MSG_INFO, "No WSL found."); + msg_printf(NULL, MSG_INFO, "WSL is not present or is not allowed by configuration file. For more details see https://github.com/BOINC/boinc/wiki/Client-configuration"); } #endif @@ -280,6 +280,38 @@ void CLIENT_STATE::show_host_info() { } #endif } +#ifdef _WIN64 + if (host_info.docker_available) { + msg_printf(NULL, MSG_INFO, "Docker is present on next WSLs:"); + for (size_t i = 0; i < host_info.wsls.wsls.size(); ++i) { + const WSL& wsl = host_info.wsls.wsls[i]; + if (wsl.is_docker_available) { + msg_printf(NULL, MSG_INFO, " [%s]: Docker version is: %s", wsl.distro_name.c_str(), wsl.docker_version.c_str()); + } + } +#else + if (host_info.docker_available && strlen(host_info.docker_version)) { + msg_printf(NULL, MSG_INFO, "Docker %s is present", host_info.docker_version); +#endif + } else { + msg_printf(NULL, MSG_INFO, "Docker is not present"); + } +#ifdef _WIN64 + if (host_info.docker_compose_available) { + msg_printf(NULL, MSG_INFO, "Docker compose is present on next WSLs:"); + for (size_t i = 0; i < host_info.wsls.wsls.size(); ++i) { + const WSL& wsl = host_info.wsls.wsls[i]; + if (wsl.is_docker_compose_available) { + msg_printf(NULL, MSG_INFO, " [%s]: Docker compose version is: %s", wsl.distro_name.c_str(), wsl.docker_compose_version.c_str()); + } + } +#else + if (host_info.docker_compose_available && strlen(host_info.docker_compose_version)) { + msg_printf(NULL, MSG_INFO, "Docker compose %s is present", host_info.docker_compose_version); +#endif + } else { + msg_printf(NULL, MSG_INFO, "Docker compose is not present"); + } } // TODO: the following 3 should be members of COPROCS diff --git a/client/cs_statefile.cpp b/client/cs_statefile.cpp index 8e44aca305f..71c6075ccc1 100644 --- a/client/cs_statefile.cpp +++ b/client/cs_statefile.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. -// http://boinc.berkeley.edu -// Copyright (C) 2022 University of California +// https://boinc.berkeley.edu +// Copyright (C) 2024 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -970,6 +970,13 @@ int CLIENT_STATE::parse_app_info(PROJECT* p, FILE* in) { delete avp; continue; } + if (cc_config.dont_use_docker && strstr(avp->plan_class, "docker")) { + msg_printf(p, MSG_INFO, + "skipping docker app in app_info.xml; docker disabled in cc_config.xml" + ); + delete avp; + continue; + } if (strlen(avp->platform) == 0) { safe_strcpy(avp->platform, get_primary_platform()); } diff --git a/client/hostinfo_unix.cpp b/client/hostinfo_unix.cpp index 358a8a3d814..24405bca9d0 100644 --- a/client/hostinfo_unix.cpp +++ b/client/hostinfo_unix.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. -// http://boinc.berkeley.edu -// Copyright (C) 2021 University of California +// https://boinc.berkeley.edu +// Copyright (C) 2024 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -20,7 +20,6 @@ // Try to keep this well-organized and not nested. #include "version.h" // version numbers from autoconf - #include "cpp.h" #include "config.h" @@ -1231,10 +1230,47 @@ int HOST_INFO::get_virtualbox_version() { pclose(fd); } } - return 0; } +// check if docker compose is installed on volunteer's host +// populates docker compose version and docker_compose_available on success +bool HOST_INFO::get_docker_compose_info(){ + FILE* f = popen(command_get_docker_compose_version, "r"); + if (f) { + char buf[256]; + fgets(buf, 256, f); + std::string version; + if (get_docker_compose_version_string(buf, version)) { + docker_compose_available = true; + safe_strcpy(docker_compose_version, version.c_str()); + } + pclose(f); + return true; + } + return false; +} + + +// check if docker is installed on volunteer's host +// populates docker version and docker_available on success +bool HOST_INFO::get_docker_info(){ + FILE* f = popen(command_get_docker_version, "r"); + if (f) { + char buf[256]; + fgets(buf, 256, f); + std::string version; + if (get_docker_version_string(buf, version)) { + docker_available = true; + safe_strcpy(docker_version, version.c_str()); + } + pclose(f); + return true; + } + return false; +} + + // get p_vendor, p_model, p_features // int HOST_INFO::get_cpu_info() { @@ -1682,6 +1718,11 @@ int HOST_INFO::get_host_info(bool init) { get_virtualbox_version(); } + if(!cc_config.dont_use_docker){ + get_docker_info(); + get_docker_compose_info(); + } + get_cpu_info(); get_cpu_count(); get_memory_info(); diff --git a/client/hostinfo_win.cpp b/client/hostinfo_win.cpp index dbfb29bfabc..a38cb26b87d 100644 --- a/client/hostinfo_win.cpp +++ b/client/hostinfo_win.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. -// http://boinc.berkeley.edu -// Copyright (C) 2018 University of California +// https://boinc.berkeley.edu +// Copyright (C) 2024 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -1550,7 +1550,6 @@ int get_network_usage_totals(unsigned int& total_received, unsigned int& total_s return iRetVal; } - // see if Virtualbox is installed // int HOST_INFO::get_virtualbox_version() { @@ -1670,7 +1669,7 @@ int HOST_INFO::get_host_info(bool init) { if (!cc_config.dont_use_wsl) { OSVERSIONINFOEX osvi; if (get_OSVERSIONINFO(osvi) && osvi.dwMajorVersion >= 10) { - get_wsl_information(wsl_available, wsls); + get_wsl_information(cc_config.allowed_wsls, wsl_available, wsls, !cc_config.dont_use_docker, docker_available, docker_compose_available); } } #endif diff --git a/client/hostinfo_wsl.cpp b/client/hostinfo_wsl.cpp index 7c115977544..e625daffdf4 100644 --- a/client/hostinfo_wsl.cpp +++ b/client/hostinfo_wsl.cpp @@ -20,7 +20,7 @@ #include "boinc_win.h" #include "str_replace.h" - +#include "client_msgs.h" #include "hostinfo.h" bool get_available_wsls(std::vector>& wsls, std::string& default_wsl) { @@ -98,15 +98,73 @@ bool get_available_wsls(std::vector>& wsls, std::s typedef HRESULT(WINAPI *PWslLaunch)(PCWSTR, PCWSTR, BOOL, HANDLE, HANDLE, HANDLE, HANDLE*); -HINSTANCE wsl_lib = NULL; +struct WSL_RESOURCE_MANAGER { + HINSTANCE wsl_lib = NULL; + HANDLE in_read = NULL; + HANDLE in_write = NULL; + HANDLE out_read = NULL; + HANDLE out_write = NULL; + PWslLaunch pWslLaunch = NULL; + + ~WSL_RESOURCE_MANAGER() { + close_handle(in_read); + close_handle(in_write); + close_handle(out_read); + close_handle(out_write); + + if (wsl_lib) { + FreeLibrary(wsl_lib); + } + } -HANDLE in_read = NULL; -HANDLE in_write = NULL; -HANDLE out_read = NULL; -HANDLE out_write = NULL; + // prepare resources + int prepare_resources() { + wsl_lib = NULL; + in_read = NULL; + in_write = NULL; + out_read = NULL; + out_write = NULL; + pWslLaunch = NULL; + + wsl_lib = LoadLibrary("wslapi.dll"); + if (!wsl_lib) { + return 1; + } + + pWslLaunch = (PWslLaunch)GetProcAddress(wsl_lib, "WslLaunch"); + + if (!pWslLaunch) { + return 1; + } -PWslLaunch pWslLaunch = NULL; + SECURITY_ATTRIBUTES sa; + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.bInheritHandle = TRUE; + sa.lpSecurityDescriptor = NULL; + if (!CreatePipe(&out_read, &out_write, &sa, 0)) { + return 1; + } + if (!SetHandleInformation(out_read, HANDLE_FLAG_INHERIT, 0)) { + return 1; + } + if (!CreatePipe(&in_read, &in_write, &sa, 0)) { + return 1; + } + if (!SetHandleInformation(in_write, HANDLE_FLAG_INHERIT, 0)) { + return 1; + } + + return 0; + } + +private: + inline void close_handle(HANDLE handle) { + if (handle) { + CloseHandle(handle); + } + } +}; //convert std::string to PCWSTR //taken from https://stackoverflow.com/questions/27220/how-to-convert-stdstring-to-lpcwstr-in-c-unicode @@ -121,11 +179,11 @@ std::wstring s2ws(const std::string& s) return r; } -bool create_wsl_process(const std::string& wsl_distro_name, const std::string& command, HANDLE* handle, bool use_current_work_dir = false) { - return (pWslLaunch(s2ws(wsl_distro_name).c_str(), s2ws(command).c_str(), use_current_work_dir, in_read, out_write, out_write, handle) == S_OK); +bool create_wsl_process(const WSL_RESOURCE_MANAGER& rs, const std::string& wsl_distro_name, const std::string& command, HANDLE* handle, bool use_current_work_dir = false) { + return (rs.pWslLaunch(s2ws(wsl_distro_name).c_str(), s2ws(command).c_str(), use_current_work_dir, rs.in_read, rs.out_write, rs.out_write, handle) == S_OK); } -bool CreateWslProcess(const std::string& wsl_app, const std::string& command, HANDLE& handle) { +bool CreateWslProcess(const HANDLE& out_write, const std::string& wsl_app, const std::string& command, HANDLE& handle) { PROCESS_INFORMATION pi; STARTUPINFO si; @@ -152,26 +210,7 @@ bool CreateWslProcess(const std::string& wsl_app, const std::string& command, HA return res; } -inline void close_handle(HANDLE handle) { - if (handle) { - CloseHandle(handle); - } -} - -int free_resources_and_exit(const int return_code) { - close_handle(in_read); - close_handle(in_write); - close_handle(out_read); - close_handle(out_write); - - if (wsl_lib) { - FreeLibrary(wsl_lib); - } - - return return_code; -} - -std::string read_from_pipe(HANDLE handle) { +std::string read_from_pipe(const HANDLE& handle, const HANDLE& out_read) { DWORD avail, read, exitcode; const int bufsize = 256; char buf[bufsize]; @@ -222,59 +261,42 @@ void parse_sysctl_output(const std::vector& lines, std::string& ost // Returns the OS name and version for WSL when enabled // -int get_wsl_information(bool& wsl_available, WSLS& wsls) { - wsl_lib = NULL; - in_read = NULL; - in_write = NULL; - out_read = NULL; - out_write = NULL; - pWslLaunch = NULL; - +bool get_wsl_information(std::vector allowed_wsls, bool& wsl_available, WSLS& wsls, bool detect_docker, bool& docker_available, bool& docker_compose_available) { std::vector> distros; std::string default_distro; if (!get_available_wsls(distros, default_distro)) { - return 1; - } - - wsl_lib = LoadLibrary("wslapi.dll"); - if (!wsl_lib) { - return 1; + return false; } - pWslLaunch = (PWslLaunch) GetProcAddress(wsl_lib, "WslLaunch"); + WSL_RESOURCE_MANAGER rs; - if (!pWslLaunch) { - free_resources_and_exit(1); + if (rs.prepare_resources()) { + return false; } wsl_available = false; + docker_available = false; + docker_compose_available = false; - SECURITY_ATTRIBUTES sa; HANDLE handle; - sa.nLength = sizeof(SECURITY_ATTRIBUTES); - sa.bInheritHandle = TRUE; - sa.lpSecurityDescriptor = NULL; - - if (!CreatePipe(&out_read, &out_write, &sa, 0)) { - return 1; - } - if (!SetHandleInformation(out_read, HANDLE_FLAG_INHERIT, 0)) { - return free_resources_and_exit(1); - } - if (!CreatePipe(&in_read, &in_write, &sa, 0)) { - return free_resources_and_exit(1); - } - if (!SetHandleInformation(in_write, HANDLE_FLAG_INHERIT, 0)) { - return free_resources_and_exit(1); - } - for (size_t i = 0; i < distros.size(); ++i) { char wsl_dist_name[256]; char wsl_dist_version[256]; const std::string& distro = distros[i].first; + // skip 'docker-desktop-data' + // Ref: https://stackoverflow.com/a/61431088/4210508 + if (distro == "docker-desktop-data"){ + continue; + } + // skip distros that are not allowed except for 'docker-desktop' + if (distro != "docker-desktop" && std::find(allowed_wsls.begin(), allowed_wsls.end(), distro) == allowed_wsls.end()) { + msg_printf(0, MSG_INFO, "WSL distro '%s' detected but is not allowed", distro.c_str()); + continue; + } + WSL wsl; wsl.distro_name = distro; if (distro == default_distro) { @@ -285,32 +307,32 @@ int get_wsl_information(bool& wsl_available, WSLS& wsls) { wsl.wsl_version = std::to_string(distros[i].second); // lsbrelease - if (!create_wsl_process(distro, command_lsbrelease, &handle)) { + if (!create_wsl_process(rs, distro, command_lsbrelease, &handle)) { continue; } wsl_available = HOST_INFO::parse_linux_os_info( - read_from_pipe(handle), lsbrelease, wsl_dist_name, sizeof(wsl_dist_name), wsl_dist_version, sizeof(wsl_dist_version)); + read_from_pipe(handle, rs.out_read), lsbrelease, wsl_dist_name, sizeof(wsl_dist_name), wsl_dist_version, sizeof(wsl_dist_version)); CloseHandle(handle); if (!wsl_available) { //osrelease const std::string command_osrelease = "cat " + std::string(file_osrelease); - if (!create_wsl_process(distro, command_osrelease, &handle)) { + if (!create_wsl_process(rs, distro, command_osrelease, &handle)) { continue; } wsl_available = HOST_INFO::parse_linux_os_info( - read_from_pipe(handle), osrelease, wsl_dist_name, sizeof(wsl_dist_name), wsl_dist_version, sizeof(wsl_dist_version)); + read_from_pipe(handle, rs.out_read), osrelease, wsl_dist_name, sizeof(wsl_dist_name), wsl_dist_version, sizeof(wsl_dist_version)); CloseHandle(handle); } //redhatrelease if (!wsl_available) { const std::string command_redhatrelease = "cat " + std::string(file_redhatrelease); - if (!create_wsl_process(distro, command_redhatrelease, &handle)) { + if (!create_wsl_process(rs, distro, command_redhatrelease, &handle)) { continue; } wsl_available = HOST_INFO::parse_linux_os_info( - read_from_pipe(handle), redhatrelease, wsl_dist_name, sizeof(wsl_dist_name), wsl_dist_version, sizeof(wsl_dist_version)); + read_from_pipe(handle, rs.out_read), redhatrelease, wsl_dist_name, sizeof(wsl_dist_name), wsl_dist_version, sizeof(wsl_dist_version)); CloseHandle(handle); } @@ -323,16 +345,16 @@ int get_wsl_information(bool& wsl_available, WSLS& wsls) { // sysctl -a const std::string command_sysctl = "sysctl -a"; - if (create_wsl_process(distro, command_sysctl, &handle)) { - parse_sysctl_output(split(read_from_pipe(handle), '\n'), os_name, os_version_extra); + if (create_wsl_process(rs, distro, command_sysctl, &handle)) { + parse_sysctl_output(split(read_from_pipe(handle, rs.out_read), '\n'), os_name, os_version_extra); CloseHandle(handle); } // uname -s if (os_name.empty()) { const std::string command_uname_s = "uname -s"; - if (create_wsl_process(distro, command_uname_s, &handle)) { - os_name = read_from_pipe(handle); + if (create_wsl_process(rs, distro, command_uname_s, &handle)) { + os_name = read_from_pipe(handle, rs.out_read); strip_whitespace(os_name); CloseHandle(handle); } @@ -341,8 +363,8 @@ int get_wsl_information(bool& wsl_available, WSLS& wsls) { // uname -r if (os_version_extra.empty()) { const std::string command_uname_r = "uname -r"; - if (create_wsl_process(distro, command_uname_r ,&handle)) { - os_version_extra = read_from_pipe(handle); + if (create_wsl_process(rs, distro, command_uname_r ,&handle)) { + os_version_extra = read_from_pipe(handle, rs.out_read); strip_whitespace(os_version_extra); CloseHandle(handle); } @@ -360,10 +382,34 @@ int get_wsl_information(bool& wsl_available, WSLS& wsls) { else { wsl.os_version = wsl_dist_version; } + + if (detect_docker) { + if (create_wsl_process(rs, distro, command_get_docker_version, &handle)) { + std::string raw = read_from_pipe(handle, rs.out_read); + std::string version; + wsl.is_docker_available = HOST_INFO::get_docker_version_string(raw, version); + if (wsl.is_docker_available) { + docker_available = true; + wsl.docker_version = version; + } + CloseHandle(handle); + } + if (create_wsl_process(rs, distro, command_get_docker_compose_version, &handle)) { + std::string raw = read_from_pipe(handle, rs.out_read); + std::string version; + wsl.is_docker_compose_available = HOST_INFO::get_docker_compose_version_string(raw, version); + if (wsl.is_docker_compose_available) { + docker_compose_available = true; + wsl.docker_compose_version = version; + } + CloseHandle(handle); + } + } + wsls.wsls.push_back(wsl); } - return free_resources_and_exit(0); + return true; } #endif // _WIN64 diff --git a/client/log_flags.cpp b/client/log_flags.cpp index 353da9f12ab..128cecddb45 100644 --- a/client/log_flags.cpp +++ b/client/log_flags.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. -// http://boinc.berkeley.edu -// Copyright (C) 2018 University of California +// https://boinc.berkeley.edu +// Copyright (C) 2024 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -198,6 +198,14 @@ void CC_CONFIG::show() { if (dont_use_wsl) { msg_printf(NULL, MSG_INFO, "Config: don't use the Windows Subsystem for Linux"); } + for (i=0; i%d\n" " %d\n" " %d\n" - " %d\n", + " %d\n" + " %d\n", disallow_attach, dont_check_file_sizes, dont_contact_ref_site, lower_client_priority, dont_suspend_nci, dont_use_vbox, - dont_use_wsl + dont_use_wsl, + dont_use_docker ); + for (i=0; i%s\n", + allowed_wsls[i].c_str() + ); + } + for (i=0; i allowed_wsls; + bool dont_use_docker; std::vector exclude_gpus; std::vector exclusive_apps; std::vector exclusive_gpu_apps; diff --git a/lib/hostinfo.cpp b/lib/hostinfo.cpp index fe2d792935a..c48c3fa3499 100644 --- a/lib/hostinfo.cpp +++ b/lib/hostinfo.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. -// http://boinc.berkeley.edu -// Copyright (C) 2023 University of California +// https://boinc.berkeley.edu +// Copyright (C) 2024 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -71,7 +71,15 @@ void HOST_INFO::clear_host_info() { safe_strcpy(os_name, ""); safe_strcpy(os_version, ""); +#ifdef _WIN64 wsl_available = false; +#endif + docker_available = false; + docker_compose_available = false; +#ifndef _WIN64 + safe_strcpy(docker_version, ""); + safe_strcpy(docker_compose_version, ""); +#endif #ifdef _WIN64 wsls.clear(); #endif @@ -133,11 +141,16 @@ int HOST_INFO::parse(XML_PARSER& xp, bool static_items_only) { if (xp.parse_str("os_name", os_name, sizeof(os_name))) continue; if (xp.parse_str("os_version", os_version, sizeof(os_version))) continue; #ifdef _WIN64 - if (xp.parse_bool("os_wsl_enabled", wsl_available)) continue; + if (xp.parse_bool("wsl_available", wsl_available)) continue; if (xp.match_tag("wsl")) { this->wsls.parse(xp); continue; } +#endif + if (xp.parse_bool("docker_available", docker_available)) continue; +#ifndef _WIN64 + if (xp.parse_str("docker_version", docker_version, sizeof(docker_version))) continue; + if (xp.parse_str("docker_compose_version", docker_compose_version, sizeof(docker_compose_version))) continue; #endif if (xp.parse_str("product_name", product_name, sizeof(product_name))) continue; if (xp.parse_str("virtualbox_version", virtualbox_version, sizeof(virtualbox_version))) continue; @@ -207,7 +220,8 @@ int HOST_INFO::write( " %s\n" " %s\n" " %d\n" - " %d\n", + " %d\n" + " %d\n", host_cpid, p_ncpus, pv, @@ -227,15 +241,30 @@ int HOST_INFO::write( osv, coprocs.ndevs(), #ifdef _WIN64 - wsl_available ? 1 : 0 + wsl_available ? 1 : 0, #else - 0 + 0, #endif + docker_available ? 1 : 0 ); #ifdef _WIN64 if (wsl_available) { wsls.write_xml(out); } +#endif +#ifndef _WIN64 + if (strlen(docker_version)) { + out.printf( + " %s\n", + docker_version + ); + } + if (strlen(docker_compose_version)) { + out.printf( + " %s\n", + docker_compose_version + ); + } #endif if (strlen(product_name)) { xml_escape(product_name, pn, sizeof(pn)); @@ -258,6 +287,20 @@ int HOST_INFO::write( buf ); } +#ifndef _WIN64 + if (docker_available){ + out.printf( + " %s\n", + docker_version + ); + } + if (docker_compose_available){ + out.printf( + " %s\n", + docker_compose_version + ); + } +#endif if (include_coprocs) { this->coprocs.write_xml(out, false); } @@ -317,3 +360,33 @@ int HOST_INFO::write_cpu_benchmarks(FILE* out) { ); return 0; } + +bool HOST_INFO::get_docker_version_string(std::string raw, std::string& parsed) { + std::string prefix = "Docker version"; + size_t pos1 = raw.find(prefix); + if (pos1 == std::string::npos) { + return false; + } + size_t pos2 = raw.find(","); + if (pos2 == std::string::npos) { + return false; + } + parsed = raw.substr(pos1 + prefix.size() + 1, pos2 - pos1 - prefix.size() - 1); + if (!parsed.empty() && parsed[parsed.length() - 1] == '\n') { + parsed.erase(parsed.length() - 1); + } + return true; +} +bool HOST_INFO::get_docker_compose_version_string(std::string raw, std::string& parsed) { + std::string prefix = "Docker Compose version v"; + size_t pos1 = raw.find(prefix); + if (pos1 == std::string::npos) { + return false; + } + parsed = raw.substr(pos1 + prefix.size(), raw.size() - pos1 - prefix.size()); + if (!parsed.empty() && parsed[parsed.length() - 1] == '\n') { + parsed.erase(parsed.length() - 1); + } + return true; +} + diff --git a/lib/hostinfo.h b/lib/hostinfo.h index 19859857cb4..83546d2d566 100644 --- a/lib/hostinfo.h +++ b/lib/hostinfo.h @@ -47,6 +47,8 @@ enum LINUX_OS_INFO_PARSER { const char command_lsbrelease[] = "/usr/bin/lsb_release -a 2>&1"; const char file_osrelease[] = "/etc/os-release"; const char file_redhatrelease[] = "/etc/redhat-release"; +const char command_get_docker_version[] = "docker --version"; +const char command_get_docker_compose_version[] = "docker compose version"; // if you add fields, update clear_host_info() @@ -80,9 +82,19 @@ class HOST_INFO { char os_name[256]; char os_version[256]; + bool docker_available; + bool docker_compose_available; +#ifndef _WIN64 + // on Windows we can have several docker installation within WSL + // that is why it makes no sense to have this information put here + // instead the information about the available 'docker' and 'docker compose' + // installations should be taken from every particular WSL distro + char docker_version[256]; + char docker_compose_version[256]; +#endif +#ifdef _WIN64 // WSL information for Win10 only bool wsl_available; -#ifdef _WIN64 WSLS wsls; #endif @@ -124,6 +136,14 @@ class HOST_INFO { int get_host_battery_state(); int get_local_network_info(); int get_virtualbox_version(); +#ifndef _WIN64 + // on Windows we can have several docker installation within WSL + // that is why it makes no sense to have this information put here + // instead the information about the available 'docker' and 'docker compose' + // installations should be taken from every particular WSL distro + bool get_docker_info(); + bool get_docker_compose_info(); +#endif void make_random_string(const char* salt, char* out); void generate_host_cpid(); static bool parse_linux_os_info( @@ -142,6 +162,8 @@ class HOST_INFO { char* os_name, const int os_name_size, char* os_version, const int os_version_size ); + static bool get_docker_version_string(std::string raw, std::string& parsed); + static bool get_docker_compose_version_string(std::string raw, std::string& parsed); #ifdef _WIN32 void win_get_processor_info(); #endif @@ -150,7 +172,7 @@ class HOST_INFO { extern void make_secure_random_string(char*); #ifdef _WIN64 -extern int get_wsl_information(bool& wsl_available, WSLS& wsls); +extern bool get_wsl_information(std::vector allowed_wsls, bool& wsl_available, WSLS& wsls, bool detect_docker, bool& docker_available, bool& docker_compose_available); extern int get_processor_group(HANDLE); #endif diff --git a/lib/wslinfo.cpp b/lib/wslinfo.cpp index f39091e6191..5f4355884b6 100644 --- a/lib/wslinfo.cpp +++ b/lib/wslinfo.cpp @@ -27,6 +27,10 @@ void WSL::clear() { os_version = ""; is_default = false; wsl_version = "1"; + is_docker_available = false; + is_docker_compose_available = false; + docker_version = ""; + docker_compose_version = ""; } void WSL::write_xml(MIOFILE& f) { @@ -41,12 +45,20 @@ void WSL::write_xml(MIOFILE& f) { " %s\n" " %d\n" " %s\n" + " %d\n" + " %d\n" + " %s\n" + " %s\n" " \n", dn, n, v, is_default ? 1 : 0, - wsl_version.c_str() + wsl_version.c_str(), + is_docker_available ? 1 : 0, + is_docker_compose_available ? 1 : 0, + docker_version.c_str(), + docker_compose_version.c_str() ); } @@ -61,6 +73,10 @@ int WSL::parse(XML_PARSER& xp) { if (xp.parse_string("os_version", os_version)) continue; if (xp.parse_bool("is_default", is_default)) continue; if (xp.parse_string("wsl_version", wsl_version)) continue; + if (xp.parse_bool("is_docker_available", is_docker_available)) continue; + if (xp.parse_bool("is_docker_compose_available", is_docker_compose_available)) continue; + if (xp.parse_string("docker_version", docker_version)) continue; + if (xp.parse_string("docker_compose_version", docker_compose_version)) continue; } return ERR_XML_PARSE; } diff --git a/lib/wslinfo.h b/lib/wslinfo.h index 734070c882f..15680102b54 100644 --- a/lib/wslinfo.h +++ b/lib/wslinfo.h @@ -35,6 +35,14 @@ struct WSL { std::string wsl_version; // flag indicating whether this is the default WSL distribution bool is_default; + // flag indicating whether Docker is available in this WSL distribution + bool is_docker_available; + // flag indicating whether Docker Compose is available in this WSL distribution + bool is_docker_compose_available; + // version of Docker installed in this WSL distribution + std::string docker_version; + // version of Docker Compose installed in this WSL distribution + std::string docker_compose_version; WSL(); diff --git a/sched/sched_types.cpp b/sched/sched_types.cpp index 40f029475b0..71a2cbb50ce 100644 --- a/sched/sched_types.cpp +++ b/sched/sched_types.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. -// http://boinc.berkeley.edu -// Copyright (C) 2023 University of California +// https://boinc.berkeley.edu +// Copyright (C) 2024 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -1401,6 +1401,10 @@ int HOST::parse(XML_PARSER& xp) { if (xp.parse_double("n_bwup", n_bwup)) continue; if (xp.parse_double("n_bwdown", n_bwdown)) continue; if (xp.parse_str("p_features", p_features, sizeof(p_features))) continue; + if (xp.parse_bool("docker_available", docker_available)) continue; + if (xp.parse_bool("docker_compose_available", docker_compose_available)) continue; + if (xp.parse_str("docker_version", docker_version, sizeof(docker_version))) continue; + if (xp.parse_str("docker_compose_version", docker_compose_version, sizeof(docker_compose_version))) continue; if (xp.parse_str("virtualbox_version", virtualbox_version, sizeof(virtualbox_version))) continue; if (xp.parse_bool("p_vm_extensions_disabled", p_vm_extensions_disabled)) continue; if (xp.match_tag("opencl_cpu_prop")) {