From b982fae41a1b58698e0f73232276bb2ecee4f5ba Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 31 Oct 2024 19:49:04 -0700 Subject: [PATCH 1/6] client: remove unused Docker images and containers on startup The images and containers created by docker_wrapper have a particular form: boinc____ and boinc____. docker_wrapper normally cleans up after itself. But if it crashes these objects could hang around forever, taking up disk space. So we clean them up on client startup, as follows: make lists of the names for active Docker tasks. Then go through the list of Docker images and containers. Remove any that - were created by Docker wrapper (i.e. have boinc__ names) - aren't in the active-task lists On Unix, do this on the host itself if it has Docker installed. On Win, do it for every WSL distro that has Docker installed. --- client/client_state.cpp | 4 + client/client_state.h | 1 + client/cs_apps.cpp | 115 +++++++++++++++++- lib/util.cpp | 104 ++++++++++++++++ lib/util.h | 36 ++++++ lib/win_util.cpp | 8 +- lib/win_util.h | 4 +- samples/docker_wrapper/docker_wrapper.cpp | 140 ++++++---------------- 8 files changed, 296 insertions(+), 116 deletions(-) diff --git a/client/client_state.cpp b/client/client_state.cpp index 9d9904792cd..33ddbf1f749 100644 --- a/client/client_state.cpp +++ b/client/client_state.cpp @@ -15,6 +15,8 @@ // You should have received a copy of the GNU Lesser General Public License // along with BOINC. If not, see . +// client initialization and main loop + #ifdef _WIN32 #include "boinc_win.h" #else @@ -729,6 +731,8 @@ int CLIENT_STATE::init() { process_gpu_exclusions(); + docker_cleanup(); + check_clock_reset(); // Check to see if we can write the state file. diff --git a/client/client_state.h b/client/client_state.h index 3adac058f85..950ce498bc0 100644 --- a/client/client_state.h +++ b/client/client_state.h @@ -378,6 +378,7 @@ struct CLIENT_STATE { int app_finished(ACTIVE_TASK&); bool handle_finished_apps(); void check_overdue(); + void docker_cleanup(); ACTIVE_TASK* get_task(RESULT*); diff --git a/client/cs_apps.cpp b/client/cs_apps.cpp index 752f38a6930..536b502eec0 100644 --- a/client/cs_apps.cpp +++ b/client/cs_apps.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. -// http://boinc.berkeley.edu -// Copyright (C) 2008 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 @@ -16,7 +16,7 @@ // along with BOINC. If not, see . // The "policy" part of task execution is here. -// The "mechanism" part is in app.C +// The "mechanism" part is in app.cpp // #include "cpp.h" @@ -29,11 +29,14 @@ #include #endif +#include + #include "error_numbers.h" #include "filesys.h" #include "md5_file.h" #include "shmem.h" #include "util.h" +#include "url.h" #include "client_msgs.h" #include "client_state.h" @@ -382,3 +385,109 @@ void CLIENT_STATE::check_overdue() { active_tasks.report_overdue(); t = now + 86400; } + +////////////// DOCKER CLEANUP /////////////////// + +// lists of image and container names for active jobs +// +struct DOCKER_JOB_INFO { + vector images; + vector containers; + bool image_present(string name) { + return std::find(images.begin(), images.end(), name) != images.end(); + } + bool container_present(string name) { + return std::find(containers.begin(), containers.end(), name) != containers.end(); + } +}; + +// clean up a Docker installation +// (Unix: the host; Win: a WSL distro) +// +void cleanup_docker(DOCKER_JOB_INFO &info, DOCKER_CONN &dc) { + int retval; + vector out, out2; + char cmd[1024]; + string name; + + // first containers + // + retval = dc.command("ps --all", out); + if (retval) { + fprintf(stderr, "Docker command failed: ps --all\n"); + } else { + for (string line: out) { + retval = dc.parse_container_name(line, name); + if (retval) continue; + if (!docker_is_boinc_name(name.c_str())) continue; + if (info.container_present(name)) continue; + sprintf(cmd, "rm %s", name.c_str()); + retval = dc.command(cmd, out); + if (retval) { + fprintf(stderr, "Docker command failed: %s\n", cmd); + continue; + } + msg_printf(NULL, MSG_INFO, + "Removed unused Docker container: %s", name.c_str() + ); + } + } + + // then images + // + retval = dc.command("images", out); + if (retval) { + fprintf(stderr, "Docker command failed: images\n"); + } else { + for (string line: out) { + retval = dc.parse_image_name(line, name); + if (retval) continue; + if (!docker_is_boinc_name(name.c_str())) continue; + if (info.image_present(name)) continue; + sprintf(cmd, "image rm %s", name.c_str()); + retval = dc.command(cmd, out2); + if (retval) { + fprintf(stderr, "Docker command failed: %s\n", cmd); + continue; + } + msg_printf(NULL, MSG_INFO, + "Removed unused Docker image: %s", name.c_str() + ); + } + } +} + +// remove old BOINC images and containers from Docker installations +// +void CLIENT_STATE::docker_cleanup() { + // make lists of the images and containers used by active jobs + // + DOCKER_JOB_INFO info; + for (ACTIVE_TASK *atp: active_tasks.active_tasks) { + if (!strstr(atp->app_version->plan_class, "docker")) continue; + char buf[256]; + escape_project_url(atp->wup->project->master_url, buf); + string s = docker_image_name(buf, atp->wup->name); + info.images.push_back(s); + s = docker_container_name(buf, atp->result->name); + info.containers.push_back(s); + } + + // go through local Docker installations and remove + // BOINC images and containers not in the above lists + // +#ifdef _WIN32 + for (WSL_DISTR &wd: hostinfo.wsl_distros.distros) { + if (wd.docker_version.empty()) continue; + DOCKER_CONN dc; + dc.init(wd.docker_type, wd.distro_name); + cleanup_docker(info, dc); + } +#else + if (strlen(host_info.docker_version)) { + DOCKER_CONN dc; + dc.init(host_info.docker_type); + cleanup_docker(info, dc); + } +#endif +} diff --git a/lib/util.cpp b/lib/util.cpp index 2f938a6734f..21b2eb2426f 100644 --- a/lib/util.cpp +++ b/lib/util.cpp @@ -63,6 +63,7 @@ extern "C" { #include "mfile.h" #include "miofile.h" #include "parse.h" +#include "hostinfo.h" #include "util.h" using std::min; @@ -698,3 +699,106 @@ string parse_ldd_libc(const char* input) { strip_whitespace(s); return s; } + +#ifdef _WIN32 +int DOCKER_CONN::init(DOCKER_TYPE docker_type, string distro_name) { + cli_prog = docker_cli_prog(docker_type); + if (docker_type == DOCKER) { + int retval = ctl_wc.setup(); + if (retval) return retval; + retval = ctl_wc.run_program_in_wsl(distro_name, "", true); + if (retval) return retval; + } else if (docker_type == PODMAN) { + int retval = ctl_wc.setup_root(distro_name.c_str()); + if (retval) return retval; + } else { + return -1; + } + return 0; +} +#else +int DOCKER_CONN::init(DOCKER_TYPE docker_type) { + cli_prog = docker_cli_prog(docker_type); + return 0; +} +#endif + +int DOCKER_CONN::command(const char* cmd, vector out, bool verbose) { + char buf[1024]; + if (verbose) { + fprintf(stderr, "running docker command: %s\n", cmd); + } +#ifdef _WIN32 + string output; + + sprintf(buf, "%s %s; echo EOM\n", cli_prog, cmd); + write_to_pipe(ctl_wc.in_write, buf); + retval = read_from_pipe( + ctl_wc.out_read, ctl_wc.proc_handle, output, TIMEOUT, "EOM" + ); + if (retval) { + fprintf(stderr, "read_from_pipe() error: %s\n", boincerror(retval)); + return retval; + } + out = split(output, '\n'); +#else + sprintf(buf, "%s %s\n", cli_prog, cmd); + return run_command(buf, out); +#endif + if (verbose) { + fprintf(stderr, "output:\n"); + for (string line: out) { + fprintf(stderr, "%s\n", line.c_str()); + } + } +} + + +// REPOSITORY TAG IMAGE ID CREATED SIZE +// localhost/boinc__app_test__test_wu latest cbc1498dfc49 43 hours ago 121 MB + +int DOCKER_CONN::parse_image_name(string line, string &name) { + char buf[1024]; + strcpy(buf, line.c_str()); + if (strstr(buf, "REPOSITORY")) return -1; + if (strstr(buf, "localhost/") != buf) return -1; + char *p = buf + strlen("localhost/"); + char *q = strstr(p, " "); + if (!q) return -1; + *q = 0; + name = (string)p; + return 0; +} + +// CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +// 6d4877e0d071 localhost/boinc__app_test__test_wu:latest /bin/sh -c ./work... 43 hours ago Exited (0) 21 hours ago boinc__app_test__test_result + +int DOCKER_CONN::parse_container_name(string line, string &name) { + char buf[1024]; + strcpy(buf, line.c_str()); + if (strstr(buf, "CONTAINER")) return -1; + char *p = strrchr(buf, ' '); + if (!p) return -1; + name = (string)(p+1); + return 0; +} + +string docker_image_name( + const char* proj_url_esc, const char* wu_name +) { + char buf[1024]; + sprintf(buf, "boinc__%s__%s", proj_url_esc, wu_name); + return string(buf); +} + +string docker_container_name( + const char* proj_url_esc, const char* result_name +){ + char buf[1024]; + sprintf(buf, "boinc__%s__%s", proj_url_esc, result_name); + return string(buf); +} + +bool docker_is_boinc_name(const char* name) { + return strstr(name, "boinc__") == name; +} diff --git a/lib/util.h b/lib/util.h index 663856a2b71..753f8ad6ae9 100644 --- a/lib/util.h +++ b/lib/util.h @@ -26,6 +26,8 @@ #ifdef _WIN32 #include "boinc_win.h" #endif +#include "common_defs.h" + extern double dtime(); extern double dday(); extern void boinc_sleep(double); @@ -142,4 +144,38 @@ extern double simtime; #define time(x) ((int)simtime) #endif +// represents a connection to a Docker/Podman installation +// used from docker_wrapper and the client +// +struct DOCKER_CONN { + DOCKER_TYPE type; + const char* cli_prog; +#ifdef _WIN32 + WSL_CMD ctl_wc; + int init(DOCKER_TYPE type, std::string distro_name); +#else + int init(DOCKER_TYPE); +#endif + int command( + const char* cmd, std::vector out, bool verbose=false + ); + + // parse a line from "docker images" output; return name + int parse_image_name(std::string line, std::string &name); + + // parse a line from "docker ps --all" output; return name + int parse_container_name(std::string line, std::string &name); +}; + +extern std::string docker_image_name( + const char* proj_url_esc, // escaped project URL + const char* wu_name +); +extern std::string docker_container_name( + const char* proj_url_esc, // escaped project URL + const char* result_name +); +// is the name (of a Docker image or container) a BOINC name? +extern bool docker_is_boinc_name(const char* name); + #endif diff --git a/lib/win_util.cpp b/lib/win_util.cpp index 7f1812f6417..86119b813d1 100644 --- a/lib/win_util.cpp +++ b/lib/win_util.cpp @@ -258,23 +258,23 @@ PIPE_READ_RET read_from_pipe( PeekNamedPipe(pipe, NULL, 0, NULL, &avail, NULL); if (avail) { ret = ReadFile(pipe, buf, sizeof(buf) - 1, &nread, NULL); - if (!ret) return READ_ERROR; + if (!ret) return ERR_READ; buf[nread] = 0; out += buf; if (eom) { if (out.find(eom) != std::string::npos) { - return GOT_EOM; + return 0; } } } else { if (exited) { - return PROC_DIED; + return ERR_CONNECT; } Sleep(200); if (timeout) { elapsed += .2; if (elapsed > timeout) { - return TIMEOUT; + return ERR_TIMEOUT; } } if (proc_handle) { diff --git a/lib/win_util.h b/lib/win_util.h index 7f7ec02c869..0dba261b107 100644 --- a/lib/win_util.h +++ b/lib/win_util.h @@ -68,8 +68,6 @@ struct WSL_CMD { ); }; -enum PIPE_READ_RET {GOT_EOM, PROC_DIED, TIMEOUT, READ_ERROR}; - // read from the pipe until either // - we get the eom string (if any) // If you want to read at least 1 line, use "\n" @@ -77,7 +75,7 @@ enum PIPE_READ_RET {GOT_EOM, PROC_DIED, TIMEOUT, READ_ERROR}; // - there's no more data and the given timeout (if any) is reached // - a read fails // -extern PIPE_READ_RET read_from_pipe( +extern int read_from_pipe( HANDLE pipe, HANDLE proc_handle, std::string& out, diff --git a/samples/docker_wrapper/docker_wrapper.cpp b/samples/docker_wrapper/docker_wrapper.cpp index d31ebe6948d..4c5fb5edfe5 100644 --- a/samples/docker_wrapper/docker_wrapper.cpp +++ b/samples/docker_wrapper/docker_wrapper.cpp @@ -132,11 +132,7 @@ bool running; bool verbose = false; const char* config_file = "job.toml"; const char* dockerfile = "Dockerfile"; -const char* cli_prog; - -#ifdef _WIN32 -WSL_CMD ctl_wc; -#endif +DOCKER_CONN docker_conn; // parse a list of file copy specs // @@ -203,69 +199,18 @@ int error_output(vector &out) { return 0; } -inline int run_docker_command(char* cmd, vector &out) { - int retval; - if (verbose) { - fprintf(stderr, "running docker command: %s\n", cmd); - } -#ifdef _WIN32 - // Win: run the command in the WSL container - - char buf[1024]; - string output; - - sprintf(buf, "%s; echo EOM\n", cmd); - write_to_pipe(ctl_wc.in_write, buf); - retval = read_from_pipe( - ctl_wc.out_read, ctl_wc.proc_handle, output, TIMEOUT, "EOM" - ); - if (retval) { - const char* msg = ""; - switch (retval) { - case PROC_DIED: - msg = "Process died"; - break; - case TIMEOUT: - msg = "Timeout"; - break; - case READ_ERROR: - msg = "Read Error"; - break; - default: - break; - } - fprintf(stderr, "read_from_pipe() error: %s\n", msg); - return retval; - } - out = split(output, '\n'); -#else - retval = run_command(cmd, out); - if (retval) return retval; -#endif - if (verbose) { - fprintf(stderr, "output:\n"); - for (string line: out) { - fprintf(stderr, "%s\n", line.c_str()); - } - } - return 0; -} - ////////// IMAGE //////////// void get_image_name() { char *p = strrchr(aid.project_dir, '/'); - sprintf(image_name, "boinc__%s__%s", - p+1, aid.wu_name - ); + string s = docker_image_name(p+1, aid.wu_name); + strcpy(image_name, s.c_str()); } int image_exists(bool &exists) { - char cmd[256]; vector out; - sprintf(cmd, "%s images", cli_prog); - int retval = run_docker_command(cmd, out); + int retval = docker_conn.command("images", out); if (retval) return retval; string image_name_space = image_name + string(" "); for (string line: out) { @@ -281,8 +226,8 @@ int image_exists(bool &exists) { int build_image() { char cmd[256]; vector out; - sprintf(cmd, "%s build . -t %s -f %s", cli_prog, image_name, dockerfile); - int retval = run_docker_command(cmd, out); + sprintf(cmd, "build . -t %s -f %s", image_name, dockerfile); + int retval = docker_conn.command(cmd, out); if (retval) return retval; return 0; } @@ -313,7 +258,8 @@ int get_image() { void get_container_name() { char *p = strrchr(aid.project_dir, '/'); - sprintf(container_name, "boinc__%s__%s", p+1, aid.result_name); + string s = docker_container_name(p+1, aid.result_name); + strcpy(container_name, s.c_str()); } int container_exists(bool &exists) { @@ -321,10 +267,8 @@ int container_exists(bool &exists) { int retval; vector out; - sprintf(cmd, "%s ps --all --filter \"name=%s\"", - cli_prog, container_name - ); - retval = run_docker_command(cmd, out); + sprintf(cmd, "ps --all --filter \"name=%s\"", container_name); + retval = docker_conn.command(cmd, out); if (retval) return retval; for (string line: out) { if (strstr(line.c_str(), container_name)) { @@ -359,24 +303,22 @@ int create_container() { aid.project_dir, config.project_dir_mount.c_str() ); } - sprintf(cmd, "%s create --name %s %s %s %s", - cli_prog, + sprintf(cmd, "create --name %s %s %s %s", container_name, slot_cmd, project_cmd, image_name ); - retval = run_docker_command(cmd, out); + retval = docker_conn.command(cmd, out); if (retval) return retval; if (error_output(out)) return -1; // copy files into container // for (FILE_COPY &c: config.copy_to_container) { - sprintf(cmd, "%s cp %s %s:%s", - cli_prog, + sprintf(cmd, "cp %s %s:%s", c.src.c_str(), container_name, c.dst.c_str() ); - retval = run_docker_command(cmd, out); + retval = docker_conn.command(cmd, out); if (retval) return retval; if (error_output(out)) return -1; } @@ -389,11 +331,10 @@ int copy_files_from_container() { vector out; for (FILE_COPY &c: config.copy_from_container) { - sprintf(cmd, "%s cp %s:%s %s", - cli_prog, + sprintf(cmd, "cp %s:%s %s", container_name, c.src.c_str(), c.dst.c_str() ); - retval = run_docker_command(cmd, out); + retval = docker_conn.command(cmd, out); if (retval) return retval; } return 0; @@ -404,8 +345,8 @@ int copy_files_from_container() { int container_op(const char *op) { char cmd[1024]; vector out; - sprintf(cmd, "%s %s %s", cli_prog, op, container_name); - int retval = run_docker_command(cmd, out); + sprintf(cmd, "%s %s", op, container_name); + int retval = docker_conn.command(cmd, out); return retval; } @@ -418,8 +359,8 @@ void cleanup() { vector out; if (verbose) { - sprintf(cmd, "%s logs %s", cli_prog, container_name); - run_docker_command(cmd, out); + sprintf(cmd, "logs %s", container_name); + docker_conn.command(cmd, out); fprintf(stderr, "container log:\n"); for (string line : out) { fprintf(stderr, " %s\n", line.c_str()); @@ -428,11 +369,11 @@ void cleanup() { container_op("stop"); - sprintf(cmd, "%s container rm %s", cli_prog, container_name); - run_docker_command(cmd, out); + sprintf(cmd, "container rm %s", container_name); + docker_conn.command(cmd, out); - sprintf(cmd, "%s image rm %s", cli_prog, image_name); - run_docker_command(cmd, out); + sprintf(cmd, "image rm %s", image_name); + docker_conn.command(cmd, out); } void poll_client_msgs() { @@ -465,13 +406,14 @@ void poll_client_msgs() { // check whether job has exited // Note: on both Podman and Docker this takes significant CPU time // (like .03 sec) so do it infrequently (like 5 sec) +// JOB_STATUS poll_app() { char cmd[1024]; vector out; int retval; - sprintf(cmd, "%s ps --all -f \"name=%s\"", cli_prog, container_name); - retval = run_docker_command(cmd, out); + sprintf(cmd, "ps --all -f \"name=%s\"", container_name); + retval = docker_conn.command(cmd, out); if (retval) return JOB_FAIL; for (string line: out) { if (strstr(line.c_str(), container_name)) { @@ -493,10 +435,10 @@ int get_stats(RSC_USAGE &ru) { size_t n; sprintf(cmd, - "%s stats --no-stream --format \"{{.CPUPerc}} {{.MemUsage}}\" %s", - cli_prog, container_name + "stats --no-stream --format \"{{.CPUPerc}} {{.MemUsage}}\" %s", + container_name ); - retval = run_docker_command(cmd, out); + retval = docker_conn.command(cmd, out); if (retval) return -1; if (out.empty()) return -1; const char *buf = out[0].c_str(); @@ -541,19 +483,7 @@ int wsl_init() { distro_name = distro->distro_name; docker_type = distro->docker_type; } - cli_prog = docker_cli_prog(docker_type); - if (docker_type == DOCKER) { - int retval = ctl_wc.setup(); - if (retval) return retval; - retval = ctl_wc.run_program_in_wsl(distro_name, "", true); - if (retval) return retval; - } else if (docker_type == PODMAN) { - int retval = ctl_wc.setup_root(distro_name.c_str()); - if (retval) return retval; - } else { - return -1; - } - return 0; + return docker_conn.init (docker_type, distro_name); } #endif @@ -624,11 +554,9 @@ int main(int argc, char** argv) { boinc_finish(1); } #else - if (boinc_is_standalone()) { - cli_prog = "docker"; - } else { - cli_prog = docker_cli_prog(aid.host_info.docker_type); - } + docker_conn.init( + boinc_is_standalone()?DOCKER:aid.host_info.docker_type + ); #endif retval = container_exists(exists); From c7c8fea3208ecd6119e5570c8ddead49085a0746 Mon Sep 17 00:00:00 2001 From: davidpanderson Date: Fri, 1 Nov 2024 00:26:25 -0700 Subject: [PATCH 2/6] Win build fixes --- client/cs_apps.cpp | 2 +- lib/util.cpp | 5 ++++- lib/util.h | 2 ++ lib/win_util.cpp | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/client/cs_apps.cpp b/client/cs_apps.cpp index 536b502eec0..7ff235d6292 100644 --- a/client/cs_apps.cpp +++ b/client/cs_apps.cpp @@ -477,7 +477,7 @@ void CLIENT_STATE::docker_cleanup() { // BOINC images and containers not in the above lists // #ifdef _WIN32 - for (WSL_DISTR &wd: hostinfo.wsl_distros.distros) { + for (WSL_DISTRO &wd: host_info.wsl_distros.distros) { if (wd.docker_version.empty()) continue; DOCKER_CONN dc; dc.init(wd.docker_type, wd.distro_name); diff --git a/lib/util.cpp b/lib/util.cpp index 21b2eb2426f..fcfc3953b2e 100644 --- a/lib/util.cpp +++ b/lib/util.cpp @@ -725,6 +725,7 @@ int DOCKER_CONN::init(DOCKER_TYPE docker_type) { int DOCKER_CONN::command(const char* cmd, vector out, bool verbose) { char buf[1024]; + int retval; if (verbose) { fprintf(stderr, "running docker command: %s\n", cmd); } @@ -743,7 +744,8 @@ int DOCKER_CONN::command(const char* cmd, vector out, bool verbose) { out = split(output, '\n'); #else sprintf(buf, "%s %s\n", cli_prog, cmd); - return run_command(buf, out); + retval = run_command(buf, out); + if (retval) return retval; #endif if (verbose) { fprintf(stderr, "output:\n"); @@ -751,6 +753,7 @@ int DOCKER_CONN::command(const char* cmd, vector out, bool verbose) { fprintf(stderr, "%s\n", line.c_str()); } } + return 0; } diff --git a/lib/util.h b/lib/util.h index 753f8ad6ae9..c789364b5e3 100644 --- a/lib/util.h +++ b/lib/util.h @@ -25,6 +25,7 @@ #include #ifdef _WIN32 #include "boinc_win.h" +#include "win_util.h" #endif #include "common_defs.h" @@ -159,6 +160,7 @@ struct DOCKER_CONN { int command( const char* cmd, std::vector out, bool verbose=false ); + static const int TIMEOUT = 10; // timeout for docker commands // parse a line from "docker images" output; return name int parse_image_name(std::string line, std::string &name); diff --git a/lib/win_util.cpp b/lib/win_util.cpp index 86119b813d1..65e2ccda456 100644 --- a/lib/win_util.cpp +++ b/lib/win_util.cpp @@ -244,7 +244,7 @@ int WSL_CMD::run_program_in_wsl( return (ret == S_OK)?0:-1; } -PIPE_READ_RET read_from_pipe( +int read_from_pipe( HANDLE pipe, HANDLE proc_handle, string& out, double timeout, const char* eom ) { From 733b1f7952894fc007c695206bdc47d5efb4c805 Mon Sep 17 00:00:00 2001 From: davidpanderson Date: Sat, 2 Nov 2024 12:32:16 -0700 Subject: [PATCH 3/6] debug docker_wrapper on Linux Make 'verbose' an attribute of DOCKER_CONN. --- lib/util.cpp | 18 ++++++++++++------ lib/util.h | 10 +++++----- samples/docker_wrapper/docker_wrapper.cpp | 4 ++-- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/lib/util.cpp b/lib/util.cpp index fcfc3953b2e..c1d230e9460 100644 --- a/lib/util.cpp +++ b/lib/util.cpp @@ -701,7 +701,7 @@ string parse_ldd_libc(const char* input) { } #ifdef _WIN32 -int DOCKER_CONN::init(DOCKER_TYPE docker_type, string distro_name) { +int DOCKER_CONN::init(DOCKER_TYPE docker_type, string distro_name, bool _verbose) { cli_prog = docker_cli_prog(docker_type); if (docker_type == DOCKER) { int retval = ctl_wc.setup(); @@ -714,16 +714,18 @@ int DOCKER_CONN::init(DOCKER_TYPE docker_type, string distro_name) { } else { return -1; } + verbose = _verbose; return 0; } #else -int DOCKER_CONN::init(DOCKER_TYPE docker_type) { +int DOCKER_CONN::init(DOCKER_TYPE docker_type, bool _verbose) { cli_prog = docker_cli_prog(docker_type); + verbose = _verbose; return 0; } #endif -int DOCKER_CONN::command(const char* cmd, vector out, bool verbose) { +int DOCKER_CONN::command(const char* cmd, vector &out) { char buf[1024]; int retval; if (verbose) { @@ -745,10 +747,15 @@ int DOCKER_CONN::command(const char* cmd, vector out, bool verbose) { #else sprintf(buf, "%s %s\n", cli_prog, cmd); retval = run_command(buf, out); - if (retval) return retval; + if (retval) { + if (verbose) { + fprintf(stderr, "command failed: %s\n", boincerror(retval)); + } + return retval; + } #endif if (verbose) { - fprintf(stderr, "output:\n"); + fprintf(stderr, "command output:\n"); for (string line: out) { fprintf(stderr, "%s\n", line.c_str()); } @@ -756,7 +763,6 @@ int DOCKER_CONN::command(const char* cmd, vector out, bool verbose) { return 0; } - // REPOSITORY TAG IMAGE ID CREATED SIZE // localhost/boinc__app_test__test_wu latest cbc1498dfc49 43 hours ago 121 MB diff --git a/lib/util.h b/lib/util.h index c789364b5e3..bbd56fa58e9 100644 --- a/lib/util.h +++ b/lib/util.h @@ -151,15 +151,15 @@ extern double simtime; struct DOCKER_CONN { DOCKER_TYPE type; const char* cli_prog; + bool verbose; #ifdef _WIN32 WSL_CMD ctl_wc; - int init(DOCKER_TYPE type, std::string distro_name); + int init(DOCKER_TYPE type, std::string distro_name, bool verbose); #else - int init(DOCKER_TYPE); + int init(DOCKER_TYPE, bool verbose); #endif - int command( - const char* cmd, std::vector out, bool verbose=false - ); + int command(const char* cmd, std::vector &out); + static const int TIMEOUT = 10; // timeout for docker commands // parse a line from "docker images" output; return name diff --git a/samples/docker_wrapper/docker_wrapper.cpp b/samples/docker_wrapper/docker_wrapper.cpp index 4c5fb5edfe5..df7a4a0d1a9 100644 --- a/samples/docker_wrapper/docker_wrapper.cpp +++ b/samples/docker_wrapper/docker_wrapper.cpp @@ -483,7 +483,7 @@ int wsl_init() { distro_name = distro->distro_name; docker_type = distro->docker_type; } - return docker_conn.init (docker_type, distro_name); + return docker_conn.init(docker_type, distro_name, verbose); } #endif @@ -555,7 +555,7 @@ int main(int argc, char** argv) { } #else docker_conn.init( - boinc_is_standalone()?DOCKER:aid.host_info.docker_type + boinc_is_standalone()?DOCKER:aid.host_info.docker_type, verbose ); #endif From af7087e10e66a7330213bb235cce3d7123413699 Mon Sep 17 00:00:00 2001 From: davidpanderson Date: Sat, 2 Nov 2024 13:03:49 -0700 Subject: [PATCH 4/6] linux build fix --- client/cs_apps.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/cs_apps.cpp b/client/cs_apps.cpp index 7ff235d6292..2c01eca6be4 100644 --- a/client/cs_apps.cpp +++ b/client/cs_apps.cpp @@ -486,7 +486,7 @@ void CLIENT_STATE::docker_cleanup() { #else if (strlen(host_info.docker_version)) { DOCKER_CONN dc; - dc.init(host_info.docker_type); + dc.init(host_info.docker_type, false); cleanup_docker(info, dc); } #endif From 989f78d1ca60523b25403f07a1532d670c7a7b0b Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 2 Nov 2024 14:18:33 -0700 Subject: [PATCH 5/6] build fixes --- client/cs_apps.cpp | 2 +- client/hostinfo_linux.cpp | 4 ++++ lib/hostinfo.h | 2 +- lib/util.h | 4 ++-- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/client/cs_apps.cpp b/client/cs_apps.cpp index 2c01eca6be4..7ff235d6292 100644 --- a/client/cs_apps.cpp +++ b/client/cs_apps.cpp @@ -486,7 +486,7 @@ void CLIENT_STATE::docker_cleanup() { #else if (strlen(host_info.docker_version)) { DOCKER_CONN dc; - dc.init(host_info.docker_type, false); + dc.init(host_info.docker_type); cleanup_docker(info, dc); } #endif diff --git a/client/hostinfo_linux.cpp b/client/hostinfo_linux.cpp index b794e007205..0acad4c75a5 100644 --- a/client/hostinfo_linux.cpp +++ b/client/hostinfo_linux.cpp @@ -15,6 +15,10 @@ // You should have received a copy of the GNU Lesser General Public License // along with BOINC. If not, see . +// Functions for getting the OS name and version of a Linux system. +// This is included in the Windows build because the Win client +// needs to get info on WSL distros. + #if defined(_WIN32) && !defined(__STDWX_H__) #include "boinc_win.h" #elif defined(_WIN32) && defined(__STDWX_H__) diff --git a/lib/hostinfo.h b/lib/hostinfo.h index c365379c090..22b27c520ad 100644 --- a/lib/hostinfo.h +++ b/lib/hostinfo.h @@ -18,7 +18,7 @@ #ifndef BOINC_HOSTINFO_H #define BOINC_HOSTINFO_H -// Description of a host's hardware and software. +// struct HOST_INFO describes a host's hardware and software. // This is used a few places: // - it's part of the client's state file, client_state.xml // - it's passed in the reply to the get_host_info GUI RPC diff --git a/lib/util.h b/lib/util.h index bbd56fa58e9..51329eec580 100644 --- a/lib/util.h +++ b/lib/util.h @@ -154,9 +154,9 @@ struct DOCKER_CONN { bool verbose; #ifdef _WIN32 WSL_CMD ctl_wc; - int init(DOCKER_TYPE type, std::string distro_name, bool verbose); + int init(DOCKER_TYPE type, std::string distro_name, bool verbose=false); #else - int init(DOCKER_TYPE, bool verbose); + int init(DOCKER_TYPE, bool verbose=false); #endif int command(const char* cmd, std::vector &out); From 3645a164e6450d041cebd2059f167b57021c77f1 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 2 Nov 2024 19:45:28 -0700 Subject: [PATCH 6/6] FCGI build fix Maybe we should divide util.cpp into - things used from the scheduler and file upload handlers (where we need boinc::stdio stuff) - everything else --- lib/util.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/util.cpp b/lib/util.cpp index c1d230e9460..55312ff6943 100644 --- a/lib/util.cpp +++ b/lib/util.cpp @@ -646,7 +646,7 @@ bool process_exists(HANDLE h) { return false; } -#else +#else // _WIN32 // Unix: pthreads doesn't provide an API for getting per-thread CPU time, // so just get the process's CPU time @@ -686,7 +686,9 @@ bool process_exists(int pid) { return true; } -#endif +#endif // _WIN32 + +#ifndef _USING_FCGI_ string parse_ldd_libc(const char* input) { char *q = (char*)strchr(input, '\n'); @@ -811,3 +813,4 @@ string docker_container_name( bool docker_is_boinc_name(const char* name) { return strstr(name, "boinc__") == name; } +#endif // _USING_FCGI