. // Handler for remote job submission. // See http://boinc.berkeley.edu/trac/wiki/RemoteJobs require_once("../inc/boinc_db.inc"); require_once("../inc/submit_db.inc"); require_once("../inc/xml.inc"); require_once("../inc/dir_hier.inc"); require_once("../inc/result.inc"); require_once("../inc/submit_util.inc"); error_reporting(E_ALL); ini_set('display_errors', true); ini_set('display_startup_errors', true); function error($s) { echo "\n$s\n\n"; exit; } function authenticate_user($r, $app) { $auth = (string)$r->authenticator; if (!$auth) error("no authenticator"); $user = BoincUser::lookup("authenticator='$auth'"); if (!$user) error("bad authenticator"); $user_submit = BoincUserSubmit::lookup_userid($user->id); if (!$user_submit) error("no submit access"); if ($app && !$user_submit->submit_all) { $usa = BoincUserSubmitApp::lookup("user_id=$user->id and app_id=$app->id"); if (!$usa) { error("no submit access"); } } return array($user, $user_submit); } function get_app($r) { $name = (string)($r->batch->app_name); $app = BoincApp::lookup("name='$name'"); if (!$app) error("no app"); return $app; } function batch_flop_count($r) { $x = 0; foreach($r->batch->job as $job) { $x += (double)$job->rsc_fpops_est; } return $x; } // estimate project FLOPS based on recent average credit // function project_flops() { $x = BoincUser::sum("expavg_credit"); if ($x == 0) $x = 200; $y = 1e9*$x/200; return $y; } function est_elapsed_time($r) { // crude estimate: batch FLOPs / project FLOPS // return batch_flop_count($r) / project_flops(); } function estimate_batch($r) { $app = get_app($r); list($user, $user_submit) = authenticate_user($r, $app); $e = est_elapsed_time($r); echo "\n$e\n\n"; } function read_input_template($app) { $path = "../../templates/$app->name"."_in"; return simplexml_load_file($path); } function validate_batch($jobs, $template) { $i = 0; $n = count($template->file_info); foreach($jobs as $job) { $m = count($job->input_files); if ($n != $m) { error("wrong # of input files for job $i: need $n, got $m"); } $i++; } } $fanout = parse_config(get_config(), ""); // stage a file, and return the physical name // function stage_file($file) { global $fanout; $md5 = md5_file($file->source); if (!$md5) { error("Can't get MD5 of file $source"); } $name = "batch_$md5"; $path = dir_hier_path($name, "../../download", $fanout); if (file_exists($path)) return $name; if (!copy($file->source, $path)) { error("can't copy file from $file->source to $path"); } return $name; } // stage all the files // function stage_files(&$jobs, $template) { foreach($jobs as $job) { foreach ($job->input_files as $file) { $file->name = stage_file($file); } } } function submit_job($job, $template, $app, $batch_id, $i) { $cmd = "cd ../..; ./bin/create_work --appname $app->name --batch $batch_id --rsc_fpops_est $job->rsc_fpops_est"; if ($job->command_line) { $cmd .= " --command_line \"$job->command_line\""; } $cmd .= " --wu_name batch_".$batch_id."_".$i; foreach ($job->input_files as $file) { $cmd .= " $file->name"; } $ret = system($cmd); if ($ret === FALSE) { error("can't create job"); } } function xml_get_jobs($r) { $jobs = array(); foreach($r->batch->job as $j) { $job = null; $job->input_files = array(); $job->command_line = (string)$j->command_line; $job->rsc_fpops_est = (double)$j->rsc_fpops_est; foreach ($j->input_file as $f) { $file = null; $file->source = (string)$f->source; $job->input_files[] = $file; } $jobs[] = $job; } return $jobs; } function submit_batch($r) { $app = get_app($r); list($user, $user_submit) = authenticate_user($r, $app); $template = read_input_template($app); $jobs = xml_get_jobs($r); validate_batch($jobs, $template); stage_files($jobs, $template); $njobs = count($jobs); $now = time(); $batch_name = (string)($r->batch->batch_name); $batch_id = BoincBatch::insert( "(user_id, create_time, njobs, name, app_id) values ($user->id, $now, $njobs, '$batch_name', $app->id)" ); $i = 0; foreach($jobs as $job) { submit_job($job, $template, $app, $batch_id, $i++); } $batch = BoincBatch::lookup_id($batch_id); $batch->update("state=".BATCH_STATE_IN_PROGRESS); echo "$batch_id\n"; } function print_batch_params($batch) { $app = BoincApp::lookup_id($batch->app_id); if (!$app) $app->name = "none"; echo " $batch->id $batch->create_time $batch->est_completion_time $batch->njobs $batch->fraction_done $batch->nerror_jobs $batch->state $batch->completion_time $batch->credit_estimate $batch->credit_canonical $batch->name $app->name "; } function query_batches($r) { list($user, $user_submit) = authenticate_user($r, null); $batches = BoincBatch::enum("user_id = $user->id"); echo "\n"; foreach ($batches as $batch) { if ($batch->state < BATCH_STATE_COMPLETE) { $wus = BoincWorkunit::enum("batch = $batch->id"); $batch = get_batch_params($batch, $wus); } echo " \n"; print_batch_params($batch); echo " \n"; } echo "\n"; } function n_outfiles($wu) { $path = "../../$wu->result_template_file"; $r = simplexml_load_file($path); return count($r->file_info); } function query_batch($r) { list($user, $user_submit) = authenticate_user($r, null); $batch_id = (int)($r->batch_id); $batch = BoincBatch::lookup_id($batch_id); if (!$batch) { error("no such batch"); } if ($batch->user_id != $user->id) { error("not owner"); } $wus = BoincWorkunit::enum("batch = $batch_id"); $batch = get_batch_params($batch, $wus); echo "\n"; print_batch_params($batch); $n_outfiles = n_outfiles($wus[0]); foreach ($wus as $wu) { echo " $wu->id $wu->canonical_resultid $n_outfiles "; } echo "\n"; } function query_job($r) { list($user, $user_submit) = authenticate_user($r, null); $job_id = (int)($r->job_id); $wu = BoincWorkunit::lookup_id($job_id); if (!$wu) error("no such job"); $batch = BoincBatch::lookup_id($wu->batch); if ($batch->user_id != $user->id) { error("not owner"); } echo "\n"; $results = BoincResult::enum("workunitid=$job_id"); foreach ($results as $result) { echo " $result->name $result->id ".state_string($result)." "; if ($result->server_state == 5) { // over? $paths = get_outfile_paths($result); foreach($paths as $path) { if (is_file($path)) { $size = filesize($path); echo " $size "; } } } echo "\n"; } echo "\n"; } function handle_abort_batch($r) { list($user, $user_submit) = authenticate_user($r, null); $batch_id = (int)($r->batch_id); $batch = BoincBatch::lookup_id($batch_id); if (!$batch) error("no such batch"); if ($batch->user_id != $user->id) { error("not owner"); } abort_batch($batch); echo "1"; } function handle_retire_batch($r) { list($user, $user_submit) = authenticate_user($r, null); $batch_id = (int)($r->batch_id); $batch = BoincBatch::lookup_id($batch_id); if ($batch->user_id != $user->id) { error("not owner"); } retire_batch($batch); echo "1"; } if (0) { $r = simplexml_load_string(" x 54 "); query_batch($r); exit; } if (0) { $r = simplexml_load_string(" x 312173 "); query_job($r); exit; } if (0) { $r = simplexml_load_string(" x remote_test Aug 6 batch 2 19000000000 --t 19 http://google.com/ "); submit_batch($r); exit; } xml_header(); $r = simplexml_load_string($_POST['request']); if (!$r) { error("can't parse request message"); } switch ($r->getName()) { case 'abort_batch': handle_abort_batch($r); break; case 'estimate_batch': estimate_batch($r); break; case 'query_batch': query_batch($r); break; case 'query_batches': query_batches($r); break; case 'query_job': query_job($r); break; case 'retire_batch': handle_retire_batch($r); break; case 'submit_batch': submit_batch($r); break; default: error("bad command"); } ?>