From 0240292c9977f153ccf61f469802d4d51b4f6904 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 5 Nov 2024 19:51:17 -0800 Subject: [PATCH 1/6] docker_wrapper: always mount slot dir at WORKDIR This means that the tree rooted at WORKDIR is on the host filesystem, and therefore survives system restarts; otherwise it wouldn't. This also simplifies file access from containers. There's no need to copy input files from the slot dir to the container; they're already in the container. Similar with output files. Remove these capabilities from the wrapper. If a Docker app wants to access files in the project dir (e.g. if they're huge files, shared with other jobs) it can do so by mounting the project dir (using job.toml) and then parsing the link files. Merge the two test cases (copy and mount) into one in both standalone and app_test. --- client/app_test.cpp | 51 ++----- samples/docker_wrapper/docker_wrapper.cpp | 130 ++++-------------- .../Dockerfile_mount => test/Dockerfile} | 1 - .../docker_wrapper/{test_mount => test}/in | 0 samples/docker_wrapper/test/job.toml | 1 + samples/docker_wrapper/test/main.sh | 7 + .../{test_mount => test}/worker | 0 .../docker_wrapper/test_copy/Dockerfile_copy | 4 - samples/docker_wrapper/test_copy/infile | 1 - .../docker_wrapper/test_copy/job_copy.toml | 6 - .../docker_wrapper/test_mount/job_mount.toml | 2 - samples/docker_wrapper/test_mount/main.sh | 7 - 12 files changed, 42 insertions(+), 168 deletions(-) rename samples/docker_wrapper/{test_mount/Dockerfile_mount => test/Dockerfile} (68%) rename samples/docker_wrapper/{test_mount => test}/in (100%) create mode 100644 samples/docker_wrapper/test/job.toml create mode 100755 samples/docker_wrapper/test/main.sh rename samples/docker_wrapper/{test_mount => test}/worker (100%) delete mode 100644 samples/docker_wrapper/test_copy/Dockerfile_copy delete mode 100644 samples/docker_wrapper/test_copy/infile delete mode 100644 samples/docker_wrapper/test_copy/job_copy.toml delete mode 100644 samples/docker_wrapper/test_mount/job_mount.toml delete mode 100755 samples/docker_wrapper/test_mount/main.sh diff --git a/client/app_test.cpp b/client/app_test.cpp index 57a2a862cfd..211548bfabd 100644 --- a/client/app_test.cpp +++ b/client/app_test.cpp @@ -58,23 +58,15 @@ // app main main yes // input infile in // output outfile out -//#define APP_DOCKER_WRAPPER_COPY +//#define APP_DOCKER_WRAPPER // type physical logical copy? // app worker worker yes -// app job_copy.toml job_copy.toml yes -// app Dockerfile_copy Dockerfile_copy yes -// app docker_wrapper docker_wrapper -// input infile in yes -// output outfile out yes -//#define APP_DOCKER_WRAPPER_MOUNT -// type physical logical copy? -// app worker worker -// app job_mount.toml job_mount.toml yes -// app Dockerfile_mount Dockerfile_mount yes +// app job.toml job.toml yes +// app Dockerfile Dockerfile yes // app main.sh main.sh yes // app docker_wrapper docker_wrapper // input infile in -// output outfile out +// output outfile out yes #ifdef APP_NONE void CLIENT_STATE::app_test_init() {} @@ -210,7 +202,7 @@ void CLIENT_STATE::app_test_init() { *make_file(app->project, "worker", NULL, INPUT_FILE, false) ); #endif -#ifdef APP_DOCKER_WRAPPER_COPY +#ifdef APP_DOCKER_WRAPPER av->app_files.push_back( *make_file(app->project, "docker_wrapper.exe", NULL, MAIN_PROG, false) ); @@ -218,24 +210,10 @@ void CLIENT_STATE::app_test_init() { *make_file(app->project, "worker", NULL, INPUT_FILE, true) ); av->app_files.push_back( - *make_file(app->project, "job_copy.toml", "job.toml", INPUT_FILE, true) + *make_file(app->project, "job.toml", "job.toml", INPUT_FILE, true) ); av->app_files.push_back( - *make_file(app->project, "Dockerfile_copy", "Dockerfile", INPUT_FILE, true) - ); -#endif -#ifdef APP_DOCKER_WRAPPER_MOUNT - av->app_files.push_back( - *make_file(app->project, "docker_wrapper.exe", NULL, MAIN_PROG, false) - ); - av->app_files.push_back( - *make_file(app->project, "worker", NULL, INPUT_FILE, false) - ); - av->app_files.push_back( - *make_file(app->project, "job_copy.toml", "job.toml", INPUT_FILE, true) - ); - av->app_files.push_back( - *make_file(app->project, "Dockerfile_copy", "Dockerfile", INPUT_FILE, true) + *make_file(app->project, "Dockerfile", "Dockerfile", INPUT_FILE, true) ); #endif @@ -256,13 +234,7 @@ void CLIENT_STATE::app_test_init() { *make_file(proj, "infile", "in", INPUT_FILE, false) ); #endif -#ifdef APP_DOCKER_WRAPPER_COPY - wu->command_line = "--verbose"; - wu->input_files.push_back( - *make_file(proj, "infile", "in", INPUT_FILE, true) - ); -#endif -#ifdef APP_DOCKER_WRAPPER_MOUNT +#ifdef APP_DOCKER_WRAPPER wu->command_line = "--verbose"; wu->input_files.push_back( *make_file(proj, "infile", "in", INPUT_FILE, false) @@ -277,16 +249,11 @@ void CLIENT_STATE::app_test_init() { *make_file(proj, "outfile", "out", OUTPUT_FILE, false) ); #endif -#ifdef APP_DOCKER_WRAPPER_COPY +#ifdef APP_DOCKER_WRAPPER result->output_files.push_back( *make_file(proj, "outfile", "out", OUTPUT_FILE, true) ); #endif -#ifdef APP_DOCKER_WRAPPER_MOUNT - result->output_files.push_back( - *make_file(proj, "outfile", "out", OUTPUT_FILE, false) - ); -#endif // tell the client not to get work or run benchmarks // diff --git a/samples/docker_wrapper/docker_wrapper.cpp b/samples/docker_wrapper/docker_wrapper.cpp index df7a4a0d1a9..3b91c4d7cbe 100644 --- a/samples/docker_wrapper/docker_wrapper.cpp +++ b/samples/docker_wrapper/docker_wrapper.cpp @@ -1,25 +1,21 @@ // docker_wrapper: runs a BOINC job in a Docker container // -// runs in a directory (normally slot dir) containing +// runs in a directory (i.e. slot dir) containing // // Dockerfile // job.toml // optional job config file -// files added to container via Dockerfile -// other input files -// -// For now all files must be +// input files (link or physical) +// executable files (link or physical) // // Win: -// There must be a WSL image containing the Docker engine -// e.g. an Ubuntu image downloaded from the Windows app store. -// This image can access the host (Win) filesystem. +// There must be a WSL image containing Docker or Podman // The wrapper runs a pipe-connected shell in WSL // (running in the current dir) // and sends commands (e.g. docker commands) via the pipe. // // Unix: -// The host must have the Docker engine. +// The host must have Docker or Podman // The wrapper runs Docker commands using popen() // // Logic: @@ -50,16 +46,15 @@ // max 255 chars // we'll use: boinc____ -// standalone mode: +// standalone mode (debugging): // image name: boinc // container name: boinc // slot dir: . -// project dir (mount mode): project/ +// project dir (if any indirect files): ./project/ -// enable standalone tests on Win +// enable standalone test on Win // -#define WIN_STANDALONE_COPY 0 -#define WIN_STANDALONE_MOUNT 0 +//#define WIN_STANDALONE_TEST #include #include @@ -93,34 +88,23 @@ struct RSC_USAGE { } }; -struct FILE_COPY { - string src; - string dst; -}; - // parsed version of job.toml // struct CONFIG { - string slot_dir_mount; - // mount slot dir here + string workdir; + // WORKDIR in Dockerfile; default "/app" + // slot dir will be mounted here string project_dir_mount; - // mount project dir here - vector copy_to_container; - vector copy_from_container; + // mount project dir here in container + // default: don't mount it void print() { fprintf(stderr, "Wrapper config file:\n"); - if (!slot_dir_mount.empty()) { - fprintf(stderr, " slot dir mounted at: %s\n", slot_dir_mount.c_str()); + if (!workdir.empty()) { + fprintf(stderr, " workdir: %s\n", workdir.c_str()); } if (!project_dir_mount.empty()) { fprintf(stderr, " project dir mounted at: %s\n", project_dir_mount.c_str()); } - for (FILE_COPY c:copy_to_container) { - fprintf(stderr, " copy to:src %s dst %s\n", c.src.c_str(), c.dst.c_str()); - } - for (FILE_COPY c:copy_from_container) { - fprintf(stderr, " copy from: src %s dst %s\n", c.src.c_str(), c.dst.c_str()); - } } }; @@ -134,27 +118,9 @@ const char* config_file = "job.toml"; const char* dockerfile = "Dockerfile"; DOCKER_CONN docker_conn; -// parse a list of file copy specs -// -int parse_config_copies(const toml::Value *x, vector &copies) { - const toml::Array& ar = x->as(); - for (const toml::Value& a : ar) { - FILE_COPY copy; - const toml::Value *b = a.find("src"); - if (!b) return -1; - copy.src = b->as(); - const toml::Value *c = a.find("dst"); - if (!c) return -1; - copy.dst = c->as(); - copies.push_back(copy); - } - return 0; -} - // parse job config file // int parse_config_file() { - int retval; std::ifstream ifs(config_file); if (ifs.fail()) { return -1; @@ -166,25 +132,16 @@ int parse_config_file() { } const toml::Value &v = r.value; const toml::Value *x; - x = v.find("slot_dir_mount"); + x = v.find("workdir"); if (x) { - config.slot_dir_mount = x->as(); + config.workdir = x->as(); + } else { + config.workdir = "/app"; } x = v.find("project_dir_mount"); if (x) { config.project_dir_mount = x->as(); } - x = v.find("copy_to_container"); - if (x) { - retval = parse_config_copies(x, config.copy_to_container); - if (retval) return retval; - } - x = v.find("copy_from_container"); - if (x) { - retval = parse_config_copies(x, config.copy_from_container); - if (retval) return retval; - } - return 0; } @@ -289,13 +246,9 @@ int create_container() { retval = get_image(); if (retval) return retval; - if (config.slot_dir_mount.empty()) { - slot_cmd[0] = 0; - } else { - sprintf(slot_cmd, " -v .:%s", - config.slot_dir_mount.c_str() - ); - } + sprintf(slot_cmd, " -v .:%s", + config.workdir.c_str() + ); if (config.project_dir_mount.empty()) { project_cmd[0] = 0; } else { @@ -312,31 +265,6 @@ int create_container() { if (retval) return retval; if (error_output(out)) return -1; - // copy files into container - // - for (FILE_COPY &c: config.copy_to_container) { - sprintf(cmd, "cp %s %s:%s", - c.src.c_str(), container_name, c.dst.c_str() - ); - retval = docker_conn.command(cmd, out); - if (retval) return retval; - if (error_output(out)) return -1; - } - return 0; -} - -int copy_files_from_container() { - char cmd[1024]; - int retval; - vector out; - - for (FILE_COPY &c: config.copy_from_container) { - sprintf(cmd, "cp %s:%s %s", - container_name, c.src.c_str(), c.dst.c_str() - ); - retval = docker_conn.command(cmd, out); - if (retval) return retval; - } return 0; } @@ -505,15 +433,8 @@ int main(int argc, char** argv) { } } -#if WIN_STANDALONE_COPY - SetCurrentDirectoryA("C:/ProgramData/BOINC/slots/test_docker_copy"); - config_file = "job_copy.toml"; - dockerfile = "Dockerfile_copy"; -#endif -#if WIN_STANDALONE_MOUNT - SetCurrentDirectoryA("C:/ProgramData/BOINC/slots/test_docker_mount"); - config_file = "job_mount.toml"; - dockerfile = "Dockerfile_mount"; +#ifdef WIN_STANDALONE_TEST + SetCurrentDirectoryA("C:/ProgramData/BOINC/slots/test_docker"); #endif memset(&options, 0, sizeof(options)); @@ -590,7 +511,6 @@ int main(int argc, char** argv) { boinc_finish(1); break; case JOB_SUCCESS: - copy_files_from_container(); cleanup(); boinc_finish(0); break; diff --git a/samples/docker_wrapper/test_mount/Dockerfile_mount b/samples/docker_wrapper/test/Dockerfile similarity index 68% rename from samples/docker_wrapper/test_mount/Dockerfile_mount rename to samples/docker_wrapper/test/Dockerfile index 81933134f10..5bedf82c547 100644 --- a/samples/docker_wrapper/test_mount/Dockerfile_mount +++ b/samples/docker_wrapper/test/Dockerfile @@ -1,4 +1,3 @@ FROM debian WORKDIR /app -COPY main.sh /app CMD ./main.sh diff --git a/samples/docker_wrapper/test_mount/in b/samples/docker_wrapper/test/in similarity index 100% rename from samples/docker_wrapper/test_mount/in rename to samples/docker_wrapper/test/in diff --git a/samples/docker_wrapper/test/job.toml b/samples/docker_wrapper/test/job.toml new file mode 100644 index 00000000000..e6b0292f60d --- /dev/null +++ b/samples/docker_wrapper/test/job.toml @@ -0,0 +1 @@ +project_dir_mount = "/project" diff --git a/samples/docker_wrapper/test/main.sh b/samples/docker_wrapper/test/main.sh new file mode 100755 index 00000000000..0964c9ad062 --- /dev/null +++ b/samples/docker_wrapper/test/main.sh @@ -0,0 +1,7 @@ +#! /bin/bash + +resolve () { + sed 's/..\/..\/projects\/[^\/]*\//\/project\//; s/<\/soft_link>//' $1 | tr -d '\r\n' +} + +$(resolve worker) --nsecs 1 $(resolve in) out diff --git a/samples/docker_wrapper/test_mount/worker b/samples/docker_wrapper/test/worker similarity index 100% rename from samples/docker_wrapper/test_mount/worker rename to samples/docker_wrapper/test/worker diff --git a/samples/docker_wrapper/test_copy/Dockerfile_copy b/samples/docker_wrapper/test_copy/Dockerfile_copy deleted file mode 100644 index 7a1d838eb04..00000000000 --- a/samples/docker_wrapper/test_copy/Dockerfile_copy +++ /dev/null @@ -1,4 +0,0 @@ -FROM debian -WORKDIR /app -COPY in /app -CMD ./worker in out diff --git a/samples/docker_wrapper/test_copy/infile b/samples/docker_wrapper/test_copy/infile deleted file mode 100644 index 45959f1e175..00000000000 --- a/samples/docker_wrapper/test_copy/infile +++ /dev/null @@ -1 +0,0 @@ -A screaming comes across the sky. diff --git a/samples/docker_wrapper/test_copy/job_copy.toml b/samples/docker_wrapper/test_copy/job_copy.toml deleted file mode 100644 index df29829482a..00000000000 --- a/samples/docker_wrapper/test_copy/job_copy.toml +++ /dev/null @@ -1,6 +0,0 @@ -copy_to_container = [ - {src="worker", dst="/app/worker"} -] -copy_from_container = [ - {src="/app/out", dst="out"} -] diff --git a/samples/docker_wrapper/test_mount/job_mount.toml b/samples/docker_wrapper/test_mount/job_mount.toml deleted file mode 100644 index c7ab43ed4c1..00000000000 --- a/samples/docker_wrapper/test_mount/job_mount.toml +++ /dev/null @@ -1,2 +0,0 @@ -slot_dir_mount = "/app/slot" -project_dir_mount = "/app/project" diff --git a/samples/docker_wrapper/test_mount/main.sh b/samples/docker_wrapper/test_mount/main.sh deleted file mode 100755 index 360d35e47e7..00000000000 --- a/samples/docker_wrapper/test_mount/main.sh +++ /dev/null @@ -1,7 +0,0 @@ -#! /bin/bash - -resolve () { - sed 's/..\/..\/projects\/[^\/]*\//project\//; s/<\/soft_link>//' $1 | tr -d '\r\n' -} - -$(resolve slot/worker) --nsecs 1 $(resolve slot/in) slot/out From bb6ea61305fbad56bc23d681949217725937e57b Mon Sep 17 00:00:00 2001 From: davidpanderson Date: Wed, 6 Nov 2024 00:43:47 -0800 Subject: [PATCH 2/6] tweaks --- samples/docker_wrapper/docker_wrapper.cpp | 2 +- samples/docker_wrapper/test/in | 2 +- samples/docker_wrapper/test/infile | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 samples/docker_wrapper/test/infile diff --git a/samples/docker_wrapper/docker_wrapper.cpp b/samples/docker_wrapper/docker_wrapper.cpp index 3b91c4d7cbe..03421acb49c 100644 --- a/samples/docker_wrapper/docker_wrapper.cpp +++ b/samples/docker_wrapper/docker_wrapper.cpp @@ -54,7 +54,7 @@ // enable standalone test on Win // -//#define WIN_STANDALONE_TEST +#define WIN_STANDALONE_TEST #include #include diff --git a/samples/docker_wrapper/test/in b/samples/docker_wrapper/test/in index a318afe304e..796e53e113c 100644 --- a/samples/docker_wrapper/test/in +++ b/samples/docker_wrapper/test/in @@ -1 +1 @@ -../../projects/foobar/in +../../projects/foobar/infile diff --git a/samples/docker_wrapper/test/infile b/samples/docker_wrapper/test/infile new file mode 100644 index 00000000000..d64e6c290a1 --- /dev/null +++ b/samples/docker_wrapper/test/infile @@ -0,0 +1 @@ +A screaming comes across the sky. \ No newline at end of file From 6cd9e0f7a95458c6d35861c4d4ee248a8fef4824 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 6 Nov 2024 00:44:30 -0800 Subject: [PATCH 3/6] tweak --- samples/docker_wrapper/test/main.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/docker_wrapper/test/main.sh b/samples/docker_wrapper/test/main.sh index 0964c9ad062..542cc5ba863 100755 --- a/samples/docker_wrapper/test/main.sh +++ b/samples/docker_wrapper/test/main.sh @@ -4,4 +4,4 @@ resolve () { sed 's/..\/..\/projects\/[^\/]*\//\/project\//; s/<\/soft_link>//' $1 | tr -d '\r\n' } -$(resolve worker) --nsecs 1 $(resolve in) out +./worker --nsecs 1 $(resolve in) out From 2cd0c733c04f6fa39c2362398f9415145422f4e6 Mon Sep 17 00:00:00 2001 From: davidpanderson Date: Wed, 6 Nov 2024 17:08:15 -0800 Subject: [PATCH 4/6] debug --- client/app_test.cpp | 6 +++--- samples/docker_wrapper/docker_wrapper.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/client/app_test.cpp b/client/app_test.cpp index 211548bfabd..0175cb902b9 100644 --- a/client/app_test.cpp +++ b/client/app_test.cpp @@ -50,7 +50,7 @@ // define exactly one -#define APP_NONE +//#define APP_NONE //#define APP_WSL_WRAPPER // type physical logical copy? // app wsl_wrapper.exe wsl_wrapper.exe @@ -58,14 +58,14 @@ // app main main yes // input infile in // output outfile out -//#define APP_DOCKER_WRAPPER +#define APP_DOCKER_WRAPPER // type physical logical copy? // app worker worker yes // app job.toml job.toml yes // app Dockerfile Dockerfile yes // app main.sh main.sh yes // app docker_wrapper docker_wrapper -// input infile in +// input infile in no // output outfile out yes #ifdef APP_NONE diff --git a/samples/docker_wrapper/docker_wrapper.cpp b/samples/docker_wrapper/docker_wrapper.cpp index 03421acb49c..3b91c4d7cbe 100644 --- a/samples/docker_wrapper/docker_wrapper.cpp +++ b/samples/docker_wrapper/docker_wrapper.cpp @@ -54,7 +54,7 @@ // enable standalone test on Win // -#define WIN_STANDALONE_TEST +//#define WIN_STANDALONE_TEST #include #include From 13a7060bbc88f8dd0b513eb60d465deb51c19e74 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 6 Nov 2024 17:20:02 -0800 Subject: [PATCH 5/6] docker_wrapper: use relative path when mounting the project dir Docker chokes on the Windows-style "c:\blah..." path --- samples/docker_wrapper/docker_wrapper.cpp | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/samples/docker_wrapper/docker_wrapper.cpp b/samples/docker_wrapper/docker_wrapper.cpp index 3b91c4d7cbe..4b7a519393b 100644 --- a/samples/docker_wrapper/docker_wrapper.cpp +++ b/samples/docker_wrapper/docker_wrapper.cpp @@ -108,6 +108,7 @@ struct CONFIG { } }; +const char* project_dir; char image_name[512]; char container_name[512]; APP_INIT_DATA aid; @@ -159,8 +160,7 @@ int error_output(vector &out) { ////////// IMAGE //////////// void get_image_name() { - char *p = strrchr(aid.project_dir, '/'); - string s = docker_image_name(p+1, aid.wu_name); + string s = docker_image_name(project_dir, aid.wu_name); strcpy(image_name, s.c_str()); } @@ -214,8 +214,7 @@ int get_image() { ////////// CONTAINER //////////// void get_container_name() { - char *p = strrchr(aid.project_dir, '/'); - string s = docker_container_name(p+1, aid.result_name); + string s = docker_container_name(project_dir, aid.result_name); strcpy(container_name, s.c_str()); } @@ -252,9 +251,15 @@ int create_container() { if (config.project_dir_mount.empty()) { project_cmd[0] = 0; } else { - sprintf(project_cmd, " -v %s:%s", - aid.project_dir, config.project_dir_mount.c_str() - ); + if (boinc_is_standalone()) { + sprintf(project_cmd, " -v %s:%s", + project_dir, config.project_dir_mount.c_str() + ); + } else { + sprintf(project_cmd, " -v ../../projects/%s:%s", + project_dir, config.project_dir_mount.c_str() + ); + } } sprintf(cmd, "create --name %s %s %s %s", container_name, @@ -447,9 +452,10 @@ int main(int argc, char** argv) { verbose = true; strcpy(image_name, "boinc"); strcpy(container_name, "boinc"); - strcpy(aid.project_dir, "./project"); + project_dir = "project"; } else { boinc_get_init_data(aid); + project_dir = strrchr(aid.project_dir, '/')+1; get_image_name(); get_container_name(); } From d06999a27c53194945604447acf3912d70b0512c Mon Sep 17 00:00:00 2001 From: davidpanderson Date: Wed, 6 Nov 2024 17:33:44 -0800 Subject: [PATCH 6/6] fix app test for docker wrapper; works now on Win --- client/app_test.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/client/app_test.cpp b/client/app_test.cpp index 0175cb902b9..a273b4e176d 100644 --- a/client/app_test.cpp +++ b/client/app_test.cpp @@ -50,7 +50,7 @@ // define exactly one -//#define APP_NONE +#define APP_NONE //#define APP_WSL_WRAPPER // type physical logical copy? // app wsl_wrapper.exe wsl_wrapper.exe @@ -58,7 +58,7 @@ // app main main yes // input infile in // output outfile out -#define APP_DOCKER_WRAPPER +//#define APP_DOCKER_WRAPPER // type physical logical copy? // app worker worker yes // app job.toml job.toml yes @@ -209,6 +209,9 @@ void CLIENT_STATE::app_test_init() { av->app_files.push_back( *make_file(app->project, "worker", NULL, INPUT_FILE, true) ); + av->app_files.push_back( + *make_file(app->project, "main.sh", "main.sh", INPUT_FILE, true) + ); av->app_files.push_back( *make_file(app->project, "job.toml", "job.toml", INPUT_FILE, true) );