diff --git a/html/inc/db_conn.inc b/html/inc/db_conn.inc index b39ae8d36f5..37605a16e6f 100644 --- a/html/inc/db_conn.inc +++ b/html/inc/db_conn.inc @@ -116,8 +116,8 @@ class DbConn { function enum_general($classname, $query) { $result = $this->do_query($query); - if (!$result) return null; - $x = array(); + if (!$result) return []; + $x = []; while ($obj = $result->fetch_object($classname)) { $x[] = $obj; } @@ -133,7 +133,7 @@ class DbConn { $where_clause = "where $where_clause"; } $query = "select $fields from DBNAME.$table $where_clause $order_clause"; - return $this->enum_general($classname,$query); + return $this->enum_general($classname, $query); } function enum($table, $classname, $where_clause=null, $order_clause=null) { diff --git a/html/inc/dir_hier.inc b/html/inc/dir_hier.inc index ea898bab91b..e10a4f48ba0 100644 --- a/html/inc/dir_hier.inc +++ b/html/inc/dir_hier.inc @@ -120,9 +120,7 @@ function check_download_file($path, $dl_path) { } } -// Stage the given file, which is assumed to not be in download dir already. -// -function stage_file_basic($dir, $fname) { +function get_hier_info() { static $dl_dir = null; static $fanout = null; if (!$dl_dir) { @@ -130,12 +128,37 @@ function stage_file_basic($dir, $fname) { $dl_dir = parse_config($conf, ""); $fanout = parse_config($conf, ""); } + return [$dl_dir, $fanout]; +} + +function download_hier_path($fname) { + [$dl_dir, $fanout] = get_hier_info(); + return dir_hier_path($fname, $dl_dir, $fanout); +} + +// Stage (move, not copy) the given file, +// which is assumed to not be in download dir already. +// +function stage_file_basic($dir, $fname) { + [$dl_dir, $fanout] = get_hier_info(); $old_path = "$dir/$fname"; - $new_path = dir_hier_path($fname, $dl_dir, $fanout); + $new_path = download_hier_path($fname); $md5 = md5_file($old_path); $size = filesize($old_path); file_put_contents("$new_path.md5", "$md5 $size\n"); rename($old_path, $new_path); } +// copy the given file (with given md5/size) +// to the download dir w/ given phys name; and create .md5 file +// If phys name is already there, do nothing. +// +function stage_file_aux($path, $md5, $size, $phys_name) { + [$dl_dir, $fanout] = get_hier_info(); + $phys_path = dir_hier_path($phys_name, $dl_dir, $fanout); + if (file_exists($phys_path)) return; + copy($path, $phys_path); + file_put_contents("$phys_path.md5", "$md5 $size\n"); +} + ?> diff --git a/html/inc/result.inc b/html/inc/result.inc index 1dae1c5c764..1b3d84f1832 100644 --- a/html/inc/result.inc +++ b/html/inc/result.inc @@ -723,7 +723,7 @@ function show_result($result, $show_outfile_links=false) { } if ($show_outfile_links && $result->outcome == 1) { $fanout = parse_config(get_config(), ""); - $names = get_outfile_names($result); + $names = get_outfile_phys_names($result); $i = 0; $x = ""; foreach ($names as $name) { diff --git a/html/inc/sandbox.inc b/html/inc/sandbox.inc index 2746048f43f..620c8e4d5a0 100644 --- a/html/inc/sandbox.inc +++ b/html/inc/sandbox.inc @@ -19,14 +19,23 @@ // Utility functions for user file sandbox feature // // In this system: -// - sandbox files live in the download hierarchy, -// with names of the form sb_userid_md5 -// - each user has a "sandbox dir" project/sandbox/userid. -// The files in this have user-visible names, and contents of the form -// sb file_size file_md5 +// - each user (job submitter) has a 'sandbox' where they can store files +// on the BOINC server, via a web interface. +// These files are mutable; you can modify a file w/ a given name. +// - files are stored in a dir project/sandbox/ +// - When a file is uploaded, its size and MD5 are computed and stored +// in an 'info file' in a parallel dir, project/sandbox//.md5 +// +// Sandbox files can be used for web-based job submissions systems +// like BUDA and autodock on BOINC Central. +// Typically they are used as job input files or app files, +// in which case they are downloadable. +// When a file is used in this way, +// it must be copied to the download hierarchy, +// and assigned a physical name that includes its MD5. +// The name depends on the role of the file. require_once("../inc/util.inc"); -require_once("../inc/submit_db.inc"); require_once("../inc/dir_hier.inc"); // Return path of sandbox directory for the given user. @@ -44,75 +53,53 @@ function sandbox_dir($user) { if (!is_dir($d)) { mkdir($d); } + if (!is_dir("$d/.md5")) { + mkdir("$d/.md5"); + } return $d; } -function sandbox_write_link_file($path, $size, $md5) { - file_put_contents($path, "sb $size $md5"); -} - -// check if a link with the given md5 exists +// parse a sandbox file's info file. +// If missing, create it. // -function sandbox_lf_exists($user, $md5) { - $exist = false; - $elf = ""; +function sandbox_parse_info_file($user, $name) { $dir = sandbox_dir($user); - $files = sandbox_file_names($user); - foreach ($files as $file) { - $path = "$dir/$file"; - [$err, $file_size, $file_md5] = sandbox_parse_link_file($path); - if (!$err){ - if (strcmp($md5, $file_md5) == 0) { - $exist = true; - $elf = $file; - break; - } - } + $info_path = "$dir/.md5/$name"; + $info = parse_info_file($info_path); + if ($info) { + return $info; } - return array($exist, $elf); -} - -// parse a link file and return (error, size, md5) -// -function sandbox_parse_link_file($path) { - if (!file_exists($path)) { return array(true, null, null); } - $x = file_get_contents($path); - $n = sscanf($x, "%s %d %s", $s, $size, $md5); - if ($n != 3) return array(true, null, null); - if ($s != 'sb') return array(true, null, null); - return array(false, $size, $md5); -} - -$fanout = parse_config(get_config(), ""); - -// return the physical name of the file -// -function sandbox_file_name($user, $md5) { - return "sb_".$user->id."_".$md5; -} - -// return the path of the file in the download directory -// -function sandbox_physical_path($user, $md5) { - global $fanout; - $f = sandbox_file_name($user, $md5); - return dir_hier_path($f, parse_config(get_config(), ""), $fanout); + [$size, $md5] = get_file_info("$dir/$name"); + write_info_file($info_path, $md5, $size); + return [$md5, $size]; } // return list of files in sandbox // function sandbox_file_names($user) { - $d = opendir(sandbox_dir($user)); + $files = scandir(sandbox_dir($user)); $names = array(); - while (($f = readdir($d)) !== false) { - if ($f == '.') continue; - if ($f == '..') continue; + foreach ($files as $f) { + if ($f[0] == '.') continue; $names[] = $f; } natsort($names); return $names; } +// return list of files matching given pattern, +// in the format used for form_select() and form_select_multiple() +// +function sandbox_select_items($user, $pattern=null) { + $sbfiles = sandbox_file_names($user); + $sbitems = []; + foreach ($sbfiles as $f) { + if ($pattern && !preg_match($pattern, $f)) continue; + $sbitems[] = [$f, $f]; + } + return $sbitems; +} + // return a - Upload files to your sandbox:


+

Add file

+ "; + form_start('sandbox.php', 'post'); + form_input_hidden('action', 'add_file'); + form_input_text('Name', 'name'); + form_input_textarea('Contents', 'contents'); + form_submit('OK'); + form_end(); + echo " +
+

Sandbox contents

"; $files = array(); - while (($f = readdir($d)) !== false) { - if ($f == '.') continue; - if ($f == '..') continue; + foreach (scandir($dir) as $f) { + if ($f[0] == '.') continue; $files[] = $f; } if (count($files) == 0) { @@ -66,19 +77,10 @@ function list_files($user, $notice) { } else { sort($files); start_table(); - table_header("Name

(click to view)

", "Modified", "Size (bytes)", "MD5", "Delete","Download"); + table_header("Name

(click to view text files)

", "Modified", "Size (bytes)", "MD5", "Delete","Download"); foreach ($files as $f) { + [$md5, $size] = sandbox_parse_info_file($user, $f); $path = "$dir/$f"; - list($error, $size, $md5) = sandbox_parse_link_file($path); - if ($error) { - table_row($f, "Can't parse link file", "", "delete"); - continue; - } - $p = sandbox_physical_path($user, $md5); - if (!is_file($p)) { - table_row($f, "Physical file not found", "", ""); - continue; - } $ct = time_str(filemtime($path)); table_row( "$f", @@ -100,10 +102,13 @@ function list_files($user, $notice) { page_tail(); } +// upload one or more files + function upload_file($user) { $notice = ""; + $dir = sandbox_dir($user); $count = count($_FILES['new_file']['tmp_name']); - for ($i = 0; $i < $count; $i++) { + for ($i=0; $i<$count; $i++) { $tmp_name = $_FILES['new_file']['tmp_name'][$i]; if (!is_uploaded_file($tmp_name)) { error_page("$tmp_name is not uploaded file"); @@ -112,79 +117,65 @@ function upload_file($user) { if (strstr($name, "/")) { error_page("no / allowed"); } - $md5 = md5_file($tmp_name); - $s = stat($tmp_name); - $size = $s['size']; - [$exists, $elf] = sandbox_lf_exists($user, $md5); - if (!$exists){ - // move file to download dir - // - $phys_path = sandbox_physical_path($user, $md5); - move_uploaded_file($tmp_name, $phys_path); + if (file_exists("$dir/$name")) { + $notice .= "can't upload $name; file exists.
"; + continue; } + move_uploaded_file($tmp_name, "$dir/$name"); - // write link file + // write info file // - $dir = sandbox_dir($user); - $link_path = "$dir/$name"; - sandbox_write_link_file($link_path, $size, $md5); + [$md5, $size] = get_file_info("$dir/$name"); + write_info_file("$dir/.md5/$name", $md5, $size); + $notice .= "Uploaded file $name
"; } list_files($user, $notice); } -// delete a link to a file. -// check if currently being used by a batch. -// If the last link w/ that contents, delete the file itself +function add_file($user) { + $dir = sandbox_dir($user); + $name = post_str('name'); + if (file_exists("$dir/$name")) { + error_page("file $name exists"); + } + $contents = post_str('contents'); + $contents = str_replace("\r\n", "\n", $contents); + file_put_contents("$dir/$name", $contents); + + [$md5, $size] = get_file_info("$dir/$name"); + write_info_file("$dir/.md5/$name", $md5, $size); + + $notice = "Uploaded file $name
"; + list_files($user, $notice); +} + +// delete a sandbox file. // function delete_file($user) { $name = get_str('name'); $dir = sandbox_dir($user); - list($error, $size, $md5) = sandbox_parse_link_file("$dir/$name"); - if ($error) { - error_page("can't parse link file"); - } - $p = sandbox_physical_path($user, $md5); - if (!is_file($p)) { - error_page("physical file is missing"); - } - $bused = sandbox_file_in_use($user, $name); - if ($bused){ - $notice = "$name is being used by batch(es), you can not delete it now!
"; - } else{ - unlink("$dir/$name"); - $notice = "$name was deleted from your sandbox
"; - [$exists, $elf] = sandbox_lf_exists($user, $md5); - if (!$exists) { - unlink($p); - } - - } + unlink("$dir/$name"); + unlink("$dir/.md5/$name"); + $notice = "$name was deleted from your sandbox
"; list_files($user, $notice); - //Header("Location: sandbox.php"); } + function download_file($user) { $name = get_str('name'); $dir = sandbox_dir($user); - list($err, $size, $md5) = sandbox_parse_link_file("$dir/$name"); - if ($err) { - error_page("can't parse link file"); - } - $p = sandbox_physical_path($user, $md5); - if (!is_file($p)) { - error_page("$p does not exist!"); - } - do_download($p, $name); + do_download("$dir/$name"); } + function view_file($user) { $name = get_str('name'); $dir = sandbox_dir($user); - list($error, $size, $md5) = sandbox_parse_link_file("$dir/$name"); - if ($error) error_page("no such link file"); - $p = sandbox_physical_path($user, $md5); - if (!is_file($p)) error_page("no such physical file"); + $path = "$dir/$name"; + if (!is_file($path)) { + error_path("no such file $name"); + } echo "
\n";
-    readfile($p);
+    readfile($path);
     echo "
\n"; } @@ -197,6 +188,7 @@ function view_file($user) { switch ($action) { case '': list_files($user,""); break; case 'upload_file': upload_file($user); break; +case 'add_file': add_file($user); break; case 'delete_file': delete_file($user); break; case 'download_file': download_file($user); break; case 'view_file': view_file($user); break; diff --git a/html/user/submit.php b/html/user/submit.php index 37b2384e404..75ee59f5c16 100644 --- a/html/user/submit.php +++ b/html/user/submit.php @@ -196,27 +196,27 @@ function show_batches($batches, $limit, $user, $app) { // and a button for creating a new batch // function handle_main($user) { - global $submit_urls; + global $web_apps; $user_submit = BoincUserSubmit::lookup_userid($user->id); if (!$user_submit) { error_page("Ask the project admins for permission to submit jobs"); } - page_head("Job submission and control"); + page_head("Job submission"); - if (isset($submit_urls)) { + if (isset($web_apps) && $web_apps) { // show links to per-app job submission pages // echo "

Submit jobs

    "; - foreach ($submit_urls as $appname=>$submit_url) { + foreach ($web_apps as $appname => $web_app) { $appname = BoincDb::escape_string($appname); $app = BoincApp::lookup("name='$appname'"); - if (!$app) error_page("bad submit_url name: $appname"); + if (!$app) error_page("bad web app name: $appname"); $usa = BoincUserSubmitApp::lookup("user_id=$user->id and app_id=$app->id"); if ($usa || $user_submit->submit_all) { - echo "
  • $app->user_friendly_name "; + echo "
  • submit_url> $app->user_friendly_name "; } } echo "
\n"; @@ -254,40 +254,8 @@ function handle_main($user) { } } if ($user_submit->manage_all || $app_admin) { - echo "

Administrative functions

\n"; + echo "

Administer job submission

\n"; + show_button('submit.php?action=admin', 'Administer'); } $batches = BoincBatch::enum("user_id = $user->id order by id desc"); @@ -318,20 +286,59 @@ function check_admin_access($user, $app_id) { } } -function handle_admin($user) { - $app_id = get_int("app_id"); - check_admin_access($user, $app_id); - if ($app_id) { - $app = BoincApp::lookup_id($app_id); - if (!$app) error_page("no such app"); - page_head("Administer batches for $app->user_friendly_name"); - $batches = BoincBatch::enum("app_id = $app_id order by id desc"); - show_batches($batches, PAGE_SIZE, null, $app); +function handle_admin() { + page_head("Administer job submission"); + if ($user_submit->manage_all) { + echo "
  • All applications
    + + "; + $apps = BoincApp::enum("deprecated=0"); + foreach ($apps as $app) { + echo " +
  • $app->user_friendly_name
    + + "; + } } else { - page_head("Administer batches (all apps)"); - $batches = BoincBatch::enum("true order by id desc"); - show_batches($batches, PAGE_SIZE, null, null); + foreach ($usas as $usa) { + $app = BoincApp::lookup_id($usa->app_id); + echo "
  • $app->user_friendly_name
    + id>Batches + "; + if ($usa->manage) { + echo "· + id&action=app_version_form>Versions + "; + } + } } + echo "\n"; + page_tail(); +} + +function handle_admin_app($user) { + $app_id = get_int("app_id"); + check_admin_access($user, $app_id); + $app = BoincApp::lookup_id($app_id); + if (!$app) error_page("no such app"); + + page_head("Administer batches for $app->user_friendly_name"); + $batches = BoincBatch::enum("app_id = $app_id order by id desc"); + show_batches($batches, PAGE_SIZE, null, $app); + page_tail(); +} +function handle_admin_all($user) { + page_head("Administer batches (all apps)"); + $batches = BoincBatch::enum("true order by id desc"); + show_batches($batches, PAGE_SIZE, null, null); page_tail(); } @@ -378,7 +385,8 @@ function handle_batch_stats($user) { page_tail(); return; } - start_table(); + text_start(); + start_table('table-striped'); row2("qualifying results", $n); row2("mean WSS", size_string($wss_sum/$n)); row2("max WSS", size_string($wss_max)); @@ -387,7 +395,7 @@ function handle_batch_stats($user) { row2("mean disk usage", size_string($disk_sum/$n)); row2("max disk usage", size_string($disk_max)); end_table(); - + text_end(); page_tail(); } @@ -433,15 +441,31 @@ function progress_bar($batch, $wus, $width) { // show the details of an existing batch // function handle_query_batch($user) { + global $web_apps; + $batch_id = get_int('batch_id'); $batch = BoincBatch::lookup_id($batch_id); $app = BoincApp::lookup_id($batch->app_id); $wus = BoincWorkunit::enum("batch = $batch->id"); $batch = get_batch_params($batch, $wus); + if ($batch->user_id == $user->id) { + $owner = $user; + } else { + $owner = BoincUser::lookup_id($batch->user_id); + } + + $web_app = $web_apps[$app->name]; page_head("Batch $batch_id"); + text_start(); start_table(); row2("name", $batch->name); + if ($batch->description) { + row2('description', $batch->description); + } + if ($owner) { + row2('submitter', $owner->name); + } row2("application", $app?$app->name:'---'); row2("state", batch_state_string($batch->state)); //row2("# jobs", $batch->njobs); @@ -458,11 +482,17 @@ function handle_query_batch($user) { row2("GFLOP/hours, actual", number_format(credit_to_gflop_hours($batch->credit_canonical), 2)); row2("Output File Size", size_string(batch_output_file_size($batch->id))); end_table(); - $url = "get_output2.php?cmd=batch&batch_id=$batch->id"; + + if ($web_app->assim_move) { + $url = "get_output3.php?action=get_batch&batch_id=$batch->id"; + } else { + $url = "get_output2.php?cmd=batch&batch_id=$batch->id"; + } + echo "

    "; show_button($url, "Get zipped output files"); + echo "

    "; switch ($batch->state) { case BATCH_STATE_IN_PROGRESS: - echo "

    "; show_button( "submit.php?action=abort_batch_confirm&batch_id=$batch_id", "Abort batch" @@ -470,33 +500,33 @@ function handle_query_batch($user) { break; case BATCH_STATE_COMPLETE: case BATCH_STATE_ABORTED: - echo "

    "; show_button( "submit.php?action=retire_batch_confirm&batch_id=$batch_id", "Retire batch" ); break; } + echo "

    "; show_button("submit.php?action=batch_stats&batch_id=$batch_id", "Show memory/disk usage statistics" ); echo "

    Jobs

    \n"; start_table(); - table_header( - "Job ID and name
    click for details or to get output files", - "status", - "Canonical instance
    click to see result page on BOINC server", - "Download Results" - ); + $x = [ + "Name
    click for details", + "status" + ]; + if (!$web_app->assim_move) { + $x[] = "Download Results"; + } + row_heading_array($x); foreach($wus as $wu) { $resultid = $wu->canonical_resultid; if ($resultid) { - $x = "$resultid"; $y = 'completed'; $text = "id>Download output files"; } else { - $x = "---"; $text = "---"; if ($batch->state == BATCH_STATE_COMPLETE) { $y = 'failed'; @@ -504,40 +534,99 @@ function handle_query_batch($user) { $y = "in progress"; } } - echo " - id>$wu->id · $wu->name - $y - $x - $text - - "; + $x = [ + "id>$wu->name", + $y, + ]; + if (!$web_app->assim_move) { + $x[] = $text; + } + row_array($x); } end_table(); echo "

    Return to job control page\n"; + text_end(); page_tail(); } // show the details of a job, including links to see the output files // function handle_query_job($user) { + global $web_apps; + $wuid = get_int('wuid'); $wu = BoincWorkunit::lookup_id($wuid); if (!$wu) error_page("no such job"); - page_head("Job $wuid"); + $app = BoincApp::lookup_id($wu->appid); + $web_app = $web_apps[$app->name]; + + page_head("Job $wu->name"); + text_start(); echo " - Workunit details · + Workunit details +

    batch>Batch $wu->batch "; + echo "

    Instances

    \n"; + start_table(); + table_header( + "ID
    click for result page", + "State", + "Output files" + ); + $results = BoincResult::enum("workunitid=$wuid"); + $upload_dir = parse_config(get_config(), ""); + $fanout = parse_config(get_config(), ""); + foreach($results as $result) { + $x = [ + "id>$result->id", + state_string($result) + ]; + $i = 0; + if ($result->server_state == RESULT_SERVER_STATE_OVER) { + $phys_names = get_outfile_names($result); + $log_names = get_outfile_log_names($result); + for ($i=0; $iassim_move) { + // file is in + // project/results//__file_ + $path = sprintf('results/%s/%s__file_%s', + $wu->batch, $wu->name, $log_names[$i] + ); + $x[] = "view · download"; + } else { + // file is in upload hier + $url = sprintf( + 'get_output2.php?cmd=result&result_id=%d&file_num=%d', + $result->id, $i + ); + $path = dir_hier_path($phys_names[$i], $upload_dir, $fanout); + $s = stat($path); + $size = $s['size']; + $x[] = sprintf('%s (%s bytes)
    ', + $url, + $log_names[$i], + number_format($size) + ); + } + } + } else { + $x[] = '---'; + } + row_array($x); + } + end_table(); + // show input files // echo "

    Input files

    \n"; $x = "".$wu->xml_doc.""; $x = simplexml_load_string($x); start_table(); - table_header("Logical name
    (click to view)", + table_header("Name
    (click to view)", "Size (bytes)", "MD5" ); foreach ($x->workunit->file_ref as $fr) { @@ -554,45 +643,9 @@ function handle_query_job($user) { } } } - end_table(); - echo "

    Instances

    \n"; - start_table(); - table_header( - "Instance ID
    click for result page", - "State", "Output files
    click to view the file" - ); - $results = BoincResult::enum("workunitid=$wuid"); - $upload_dir = parse_config(get_config(), ""); - $fanout = parse_config(get_config(), ""); - foreach($results as $result) { - echo " - id>$result->id · $result->name - ".state_string($result)." - -"; - $i = 0; - if ($result->server_state == 5) { - $phys_names = get_outfile_names($result); - $log_names = get_outfile_log_names($result); - for ($i=0; $iid, $i - ); - $path = dir_hier_path($phys_names[$i], $upload_dir, $fanout); - $s = stat($path); - $size = $s['size']; - echo sprintf('%s (%s bytes)
    ', - $url, - $log_names[$i], - number_format($size) - ); - } - } - echo "\n"; - } end_table(); + text_end(); echo "

    Return to job control page\n"; page_tail(); } @@ -714,13 +767,15 @@ function handle_show_all($user) { case 'abort_batch': handle_abort_batch($user); break; case 'abort_batch_confirm': handle_abort_batch_confirm(); break; case 'admin': handle_admin($user); break; +case 'admin_app': handle_admin_app($user); break; +case 'admin_all': handle_admin_all($user); break; case 'batch_stats': handle_batch_stats($user); break; case 'query_batch': handle_query_batch($user); break; case 'query_job': handle_query_job($user); break; case 'retire_batch': handle_retire_batch($user); break; case 'retire_batch_confirm': handle_retire_batch_confirm(); break; case 'show_all': handle_show_all($user); break; -case 'toggle_loc': handle_toggle_loc($user); +case 'toggle_loc': handle_toggle_loc($user); break; default: error_page("no such action $action"); } diff --git a/samples/docker_wrapper/docker_wrapper.cpp b/samples/docker_wrapper/docker_wrapper.cpp index 4b7a519393b..1e970249b07 100644 --- a/samples/docker_wrapper/docker_wrapper.cpp +++ b/samples/docker_wrapper/docker_wrapper.cpp @@ -122,9 +122,13 @@ DOCKER_CONN docker_conn; // parse job config file // int parse_config_file() { + // defaults + config.workdir = "/app"; + std::ifstream ifs(config_file); if (ifs.fail()) { - return -1; + fprintf(stderr, "no job.toml config file\n"); + return 0; } toml::ParseResult r = toml::parse(ifs); if (!r.valid()) { @@ -136,8 +140,6 @@ int parse_config_file() { x = v.find("workdir"); if (x) { config.workdir = x->as(); - } else { - config.workdir = "/app"; } x = v.find("project_dir_mount"); if (x) { diff --git a/samples/docker_wrapper/test_buda/Dockerfile_worker_1 b/samples/docker_wrapper/test_buda/Dockerfile_worker_1 new file mode 100644 index 00000000000..d897eaff2b1 --- /dev/null +++ b/samples/docker_wrapper/test_buda/Dockerfile_worker_1 @@ -0,0 +1,3 @@ +FROM debian +WORKDIR /app +CMD ./main_2.sh diff --git a/samples/docker_wrapper/test_buda/main_2.sh b/samples/docker_wrapper/test_buda/main_2.sh new file mode 100644 index 00000000000..f07fd7a2a69 --- /dev/null +++ b/samples/docker_wrapper/test_buda/main_2.sh @@ -0,0 +1,3 @@ +#! /bin/bash + +./worker_3_x86_64-pc-linux-gnu --nsecs 20 in out diff --git a/sched/assimilator.cpp b/sched/assimilator.cpp index 3f62321003d..ca9c56db8b6 100644 --- a/sched/assimilator.cpp +++ b/sched/assimilator.cpp @@ -160,7 +160,8 @@ bool do_pass(APP& app) { retval = assimilate_handler(wu, results, canonical_result); if (retval && retval != DEFER_ASSIMILATION) { log_messages.printf(MSG_CRITICAL, - "[%s] handler error: %s; exiting\n", wu.name, boincerror(retval) + "assimilator.cpp [%s] handler error %d: %s; exiting\n", + wu.name, retval, boincerror(retval) ); exit(retval); } diff --git a/sched/file_deleter.cpp b/sched/file_deleter.cpp index a495a918775..7d5f7243bf1 100644 --- a/sched/file_deleter.cpp +++ b/sched/file_deleter.cpp @@ -17,6 +17,8 @@ // file deleter. See usage() below for usage. +// skips WUs with 'nodelete' in the name +// skips files with in the // enum sizes. RESULT_PER_ENUM is three times larger on the // assumption of 3-fold average redundancy. diff --git a/sched/sample_assimilator.cpp b/sched/sample_assimilator.cpp index eda8ce6cc62..f25f4450770 100644 --- a/sched/sample_assimilator.cpp +++ b/sched/sample_assimilator.cpp @@ -17,7 +17,7 @@ // A sample assimilator that: // 1) if success, copy the output file(s) to a directory -// ../sample_results/batchid +// ../results/batchid // If 1 output file, its name is the WU name // If >1 files, file i is named _i // 2) if failure, write a message to _error @@ -89,11 +89,9 @@ int assimilate_handler( bool file_copied = false; for (i=0; i. // A sample assimilator that only writes a log message. +// But WUs are marked as assimilated, which means file deleter +// will delete output files unless you mark them as no_delete, +// or include 'no_delete' in the WU name #include "config.h" #include diff --git a/sched/script_assimilator.cpp b/sched/script_assimilator.cpp index 5dbc6777381..deabe191c1c 100644 --- a/sched/script_assimilator.cpp +++ b/sched/script_assimilator.cpp @@ -21,12 +21,15 @@ // cmdline args to this program: // --script "scriptname arg1 ... argn" // -// The script assimilates a completed job. +// This program runs the script for each completed job. // -// arg1 ... argn represent cmdline args to be passed to the script. -// the options are: +// arg1 ... argn are 'tokens' representing cmdline args +// to be passed to the script. +// possible tokens are: // -// files list of output files of the job's canonical result +// files list of paths of output files of the canonical result +// files2 list of +// of output files of the canonical result // wu_id workunit ID // wu_name workunit name // result_id ID of the canonical result @@ -56,20 +59,22 @@ using std::vector; using std::string; -vector script; +// scriptname, followed by arguments +vector script_args; int assimilate_handler_init(int argc, char** argv) { // handle project specific arguments here for (int i=1; i paths; - retval = get_output_file_paths(canonical_result, paths); + sprintf(cmd, "../bin/%s", script_args[0].c_str()); + vector fis; + retval = get_output_file_infos(canonical_result, fis); if (retval) return retval; - for (i=1; i& fis) { if (xp.match_tag("file_ref")) { OUTPUT_FILE_INFO fi; int retval = fi.parse(xp); - if (retval) return retval; + if (retval) { + log_messages.printf(MSG_CRITICAL, + "get_output_file_infos(): error parsing %s\n", + result.xml_doc_in + ); + return retval; + } if (standalone) { - safe_strcpy(path, fi.name.c_str()); - if (!path_to_filename(fi.name, name)) { - fi.name = name; + safe_strcpy(path, fi.phys_name.c_str()); + if (!path_to_filename(fi.phys_name, name)) { + fi.phys_name = name; } } else { dir_hier_path( - fi.name.c_str(), config.upload_dir, + fi.phys_name.c_str(), config.upload_dir, config.uldl_dir_fanout, path ); } diff --git a/sched/validate_util.h b/sched/validate_util.h index 221c2d6cad5..f133dc05edc 100644 --- a/sched/validate_util.h +++ b/sched/validate_util.h @@ -27,8 +27,9 @@ // of result.xml_doc_in // struct OUTPUT_FILE_INFO { - std::string name; + std::string phys_name; std::string path; + std::string logical_name; bool optional; // sample_bitwise_validator: not an error if this file is missing bool no_validate; diff --git a/tools/create_work.cpp b/tools/create_work.cpp index 0809b37f8a5..3680943b675 100644 --- a/tools/create_work.cpp +++ b/tools/create_work.cpp @@ -25,6 +25,15 @@ // - to create a single job, with everything passed on the cmdline // - to create multiple jobs, where per-job info is passed via stdin, // one line per job +// available options here: +// --wu_name X +// --wu_template F +// --result_template F +// --remote_file url nbytes md5 +// --target_host ID +// --target_user ID +// --priority N +// phys_name1 ... // // The input files must already be staged (i.e. in the download hierarchy). @@ -436,10 +445,6 @@ int main(int argc, char** argv) { strcat(jd.result_template_path, jd.result_template_file); if (use_stdin) { - // clear the WU template name so we'll recognize a job-level one - // - strcpy(jd.wu_template_file, ""); - if (jd.assign_flag) { // if we're doing assignment we can't use the bulk-query method; // create the jobs one at a time. diff --git a/tools/query_job b/tools/query_job index 65a2b860202..9f56272f2f0 100755 --- a/tools/query_job +++ b/tools/query_job @@ -34,17 +34,17 @@ function show_wu($wu, $dir) { ." Host $host->id ($host->os_name, $host->p_vendor)\n" ." User $user->id ($user->name)\n" ; + $xmlin = simplexml_load_string( + sprintf("%s", $result->xml_doc_in) + ); $xmlout = simplexml_load_string( sprintf("%s", $result->xml_doc_out) ); $ofs = $xmlout->file_info; + $ifs = $xmlin->result->file_ref; $nofs = $ofs->count(); for ($i=0; $i<$nofs; $i++) { - if ($nofs == 1) { - $path = "$dir/$wu->name"; - } else { - $path = sprintf("$dir/%s_%d", $wu->name, $i); - } + $path = sprintf("$dir/%s__file_%s", $wu->name, $ifs[$i]->open_name); if (!is_file($path)) { die("output file $i is missing: $path\n"); } diff --git a/tools/sample_assimilate.py b/tools/sample_assimilate.py index 766c4d9c914..2f48d22bc16 100755 --- a/tools/sample_assimilate.py +++ b/tools/sample_assimilate.py @@ -1,20 +1,21 @@ #! /usr/bin/env python3 # Sample script for the script-based assimilator (sched/script_assimilator.cpp) -# Moves output files into a results/ dir hierarchy +# Moves output files into a results/ hierarchy # # Use with a config.xml command of the form -# script_assimilator -d 3 --app worker --script "sample_assimilate.py wu_name batch_id files" +# script_assimilator -d 3 --app worker --script "sample_assimilate.py wu_name batch_id files2" # With this command, this script will be invoked either as -# sample_assimilate.py wu_name batch_id outfile_path1 ... +# sample_assimilate.py wu_name batch_id outfile_path1 logical_name1 ... # or -# sample_assimilator.py --error error_code wu_name wu_id batch_id +# sample_assimilator.py --error error_code wu_name wu_id batch_id # # in the 1st case, move the output files from the upload hierarchy -# to results//_i +# to results//__file_ +# where is the file's logical name # in the 2nd case, write the error code -# to results//_error +# to results//_error import sys, os @@ -37,15 +38,13 @@ if os.system(cmd): raise Exception('%s failed'%(cmd)) - nfiles = len(sys.argv) - 3 - if nfiles == 1: - outfile_path = sys.argv[3] - cmd = 'mv %s %s/%s'%(outfile_path, outdir, wu_name) + nfiles = (len(sys.argv) - 3)//2 + for i in range(nfiles): + outfile_path = sys.argv[2*i+3] + logical_name = sys.argv[2*i+4] + cmd = 'mv %s %s/%s__file_%s'%( + outfile_path, outdir, wu_name, logical_name + ) if os.system(cmd): - raise Exception('%s failed'%(cmd)) - else: - for i in range(nfiles): - outfile_path = sys.argv[i+3] - cmd = 'mv %s %s/%s_%d'%(outfile_path, outdir, wu_name, i) - if os.system(cmd): - raise Exception('%s failed'%(cmd)) + #raise Exception('%s failed'%(cmd)) + sys.stderr.write('%s failed\n'%(cmd)) diff --git a/tools/submit_buda b/tools/submit_buda index 5b5950c3a76..add5f0abfb3 100755 --- a/tools/submit_buda +++ b/tools/submit_buda @@ -1,35 +1,40 @@ #! /usr/bin/env php