. require_once("../inc/submit_db.inc"); require_once("../inc/util.inc"); require_once("../inc/result.inc"); require_once("../inc/submit_util.inc"); require_once("../project/project.inc"); error_reporting(E_ALL); ini_set('display_errors', true); ini_set('display_startup_errors', true); define("PAGE_SIZE", 20); function state_count($batches, $state) { $n = 0; foreach ($batches as $batch) { if ($batch->state == $state) $n++; } return $n; } function show_all_link($batches, $state, $limit, $user, $app) { $n = state_count($batches, $state); if ($n > $limit) { if ($user) $userid = $user->id; else $userid = 0; if ($app) $appid = $app->id; else $appid = 0; echo "Showing the most recent $limit of $n batches. Show all $n

"; } } function show_in_progress($batches, $limit, $user, $app) { $first = true; $n = 0; foreach ($batches as $batch) { if ($batch->state != BATCH_STATE_IN_PROGRESS) continue; if ($limit && $n == $limit) break; $n++; if ($first) { $first = false; echo "

Batches in progress

\n"; if ($limit) { show_all_link($batches, BATCH_STATE_IN_PROGRESS, $limit, $user, $app); } start_table(); table_header( "Name", "ID", "User", "App", "# jobs", "Progress", "Submitted", "Logical end time
Determines priority" ); } $pct_done = (int)($batch->fraction_done*100); table_row( "id>$batch->name", "id>$batch->id", $batch->user_name, $batch->app_name, $batch->njobs, "$pct_done%", local_time_str($batch->create_time), local_time_str($batch->logical_end_time) ); } if ($first) { echo "

No in-progress batches.\n"; } else { end_table(); } } function show_complete($batches, $limit, $user, $app) { $first = true; $n = 0; foreach ($batches as $batch) { if ($batch->state != BATCH_STATE_COMPLETE) continue; if ($limit && $n == $limit) break; $n++; if ($first) { $first = false; echo "

Completed batches

\n"; if ($limit) { show_all_link($batches, BATCH_STATE_COMPLETE, $limit, $user, $app); } start_table(); table_header("name", "ID", "user", "app", "# jobs", "submitted"); } table_row( "id>$batch->name", "id>$batch->id", $batch->user_name, $batch->app_name, $batch->njobs, local_time_str($batch->create_time) ); } if ($first) { echo "

No completed batches.\n"; } else { end_table(); } } function show_aborted($batches, $limit, $user, $app) { $first = true; $n = 0; foreach ($batches as $batch) { if ($batch->state != BATCH_STATE_ABORTED) continue; if ($limit && $n == $limit) break; $n++; if ($first) { $first = false; echo "

Aborted batches

\n"; if ($limit) { show_all_link($batches, BATCH_STATE_ABORTED, $limit, $user, $app); } start_table(); table_header("name", "ID", "user", "app", "# jobs", "submitted"); } table_row( "id>$batch->name", "id>$batch->id", $batch->user_name, $batch->app_name, $batch->njobs, local_time_str($batch->create_time) ); } if (!$first) { end_table(); } } // fill in the app and user names in list of batches // function fill_in_app_and_user_names(&$batches) { foreach ($batches as $batch) { //if ($batch->state < BATCH_STATE_COMPLETE || $batch->fraction_done < 1) { // $wus = BoincWorkunit::enum("batch = $batch->id"); // $batch = get_batch_params($batch, $wus); //} $app = BoincApp::lookup_id($batch->app_id); if ($app) { $batch->app_name = $app->name; } else { $batch->app_name = "unknown"; } $user = BoincUser::lookup_id($batch->user_id); if ($user) { $batch->user_name = $user->name; } else { $batch->user_name = "missing user $batch->user_id"; } } } // show a set of batches // function show_batches($batches, $limit, $user, $app) { fill_in_app_and_user_names($batches); show_in_progress($batches, $limit, $user, $app); show_complete($batches, $limit, $user, $app); show_aborted($batches, $limit, $user, $app); } // the job submission "home page": // show the user's in-progress and completed batches, // and a button for creating a new batch // function handle_main($user) { global $submit_urls; $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"); if (isset($submit_urls)) { // show links to per-app job submission pages // echo "

Submit jobs

\n"; } // show links to admin pages if relevant // $usas = BoincUserSubmitApp::enum("user_id=$user->id"); $app_admin = false; foreach ($usas as $usa) { if ($usa->manage) { $app_admin = true; break; } } if ($user_submit->manage_all || $app_admin) { echo "

Administrative functions

\n"; } $batches = BoincBatch::enum("user_id = $user->id order by id desc"); show_batches($batches, PAGE_SIZE, $user, null); page_tail(); } function check_admin_access($user, $app_id) { $user_submit = BoincUserSubmit::lookup_userid($user->id); if (!$user_submit) error_page("no access"); if ($app_id) { if (!$user_submit->manage_all) { $usa = BoincUserSubmitApp::lookup("user_id = $user->id and app_id=$app_id"); if (!$usa) error_page("no access"); } } else { if (!$user_submit->manage_all) error_page("no access"); } } 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); } else { page_head("Administer batches (all apps)"); $batches = BoincBatch::enum("true order by id desc"); show_batches($batches, PAGE_SIZE, null, null); } page_tail(); } // show the details of an existing batch // function handle_query_batch($user) { $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); page_head("Batch $batch_id"); start_table(); row2("name", $batch->name); row2("application", $app->name); row2("state", batch_state_string($batch->state)); row2("# jobs", $batch->njobs); row2("# error jobs", $batch->nerror_jobs); //row2("logical end time", time_str($batch->logical_end_time)); row2("expiration time", time_str($batch->expire_time)); row2("progress", sprintf("%.0f%%", $batch->fraction_done*100)); if ($batch->completion_time) { row2("completed", local_time_str($batch->completion_time)); } row2("GFLOP/hours, estimated", number_format(credit_to_gflop_hours($batch->credit_estimate), 2)); row2("GFLOP/hours, actual", number_format(credit_to_gflop_hours($batch->credit_canonical), 2)); row2("Output File Size (MB)", number_format(batch_output_file_size($batch->id)/1e6,2)); end_table(); if (batch_output_file_size($batch->id) <= 1e8) { $url = boinc_get_output_files_url($user, $batch_id); show_button($url, "Get zipped output files"); } else { echo "
The output file size of this batch is too big, it will be uploaded by FTP
"; } switch ($batch->state) { case BATCH_STATE_IN_PROGRESS: echo "
"; show_button( "submit.php?action=abort_batch_confirm&batch_id=$batch_id", "Abort batch" ); 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 "

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" ); foreach($wus as $wu) { $resultid = $wu->canonical_resultid; $durl = boinc_get_wu_output_files_url($user,$wu->id); if ($resultid) { $x = "$resultid"; $y = 'completed'; $text = " Download Result Files"; } else { $x = "---"; $text = "---"; if ($batch->state == BATCH_STATE_COMPLETE) { $y = 'failed'; } else { $y = "in progress"; } } echo " id>$wu->id · $wu->name $y $x $text "; } end_table(); echo "

Return to job control page\n"; page_tail(); } // show the details of a job, including links to see the output files // function handle_query_job($user) { $wuid = get_int('wuid'); $wu = BoincWorkunit::lookup_id($wuid); if (!$wu) error_page("no such job"); page_head("Job $wuid"); echo " Workunit details · batch>Batch $wu->batch "; // 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)", "Size (bytes)", "MD5" ); foreach ($x->workunit->file_ref as $fr) { $pname = (string)$fr->file_name; $lname = (string)$fr->open_name; foreach ($x->file_info as $fi) { if ((string)$fi->name == $pname) { table_row( "url>$lname", $fi->nbytes, $fi->md5_cksum ); break; } } } 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) { $names = get_outfile_names($result); $i = 0; foreach ($names as $name) { $url = boinc_get_output_file_url($user, $result, $i++); $path = dir_hier_path($name, $upload_dir, $fanout); $s = stat($path); $size = $s['size']; echo "$name (".number_format($size)." bytes)
"; } $i++; } echo "\n"; } end_table(); echo "

Return to job control page\n"; page_tail(); } function handle_abort_batch_confirm() { $batch_id = get_int('batch_id'); page_head("Confirm abort batch"); echo " Aborting a batch will cancel all unstarted jobs. Are you sure you want to do this?

"; show_button( "submit.php?action=abort_batch&batch_id=$batch_id", "Yes - abort batch" ); echo "

Return to job control page\n"; page_tail(); } function check_access($user, $batch) { if ($user->id == $batch->user_id) return; $user_submit = BoincUserSubmit::lookup_userid($user->id); if ($user_submit->manage_all) return; $usa = BoincUserSubmitApp::lookup("user_id=$user->id and app_id=$batch->app_id"); if ($usa->manage) return; error_page("no access"); } function handle_abort_batch($user) { $batch_id = get_int('batch_id'); $batch = BoincBatch::lookup_id($batch_id); if (!$batch) error_page("no such batch"); check_access($user, $batch); abort_batch($batch); page_head("Batch aborted"); echo "

Return to job control page\n"; page_tail(); } function handle_retire_batch_confirm() { $batch_id = get_int('batch_id'); page_head("Confirm retire batch"); echo " Retiring a batch will remove all of its output files. Are you sure you want to do this?

"; show_button( "submit.php?action=retire_batch&batch_id=$batch_id", "Yes - retire batch" ); echo "

Return to job control page\n"; page_tail(); } function handle_retire_batch($user) { $batch_id = get_int('batch_id'); $batch = BoincBatch::lookup_id($batch_id); if (!$batch) error_page("no such batch"); check_access($user, $batch); retire_batch($batch); page_head("Batch retired"); echo "

Return to job control page\n"; page_tail(); } function show_batches_in_state($batches, $state) { switch ($state) { case BATCH_STATE_IN_PROGRESS: page_head("Batches in progress"); show_in_progress($batches, 0, null, null); break; case BATCH_STATE_COMPLETE: page_head("Completed batches"); show_complete($batches, 0, null, null); break; case BATCH_STATE_ABORTED: page_head("Aborted batches"); show_aborted($batches, 0, null, null); break; } page_tail(); } function handle_show_all($user) { $userid = get_int("userid"); $appid = get_int("appid"); $state = get_int("state"); if ($userid) { // user looking at their own batches // if ($userid != $user->id) error_page("wrong user"); $batches = BoincBatch::enum("user_id = $user->id and state=$state order by id desc"); fill_in_app_and_user_names($batches); show_batches_in_state($batches, $state); } else { // admin looking at batches // check_admin_access($user, $appid); if ($appid) { $app = BoincApp::lookup_id($appid); if (!$app) error_page("no such app"); $batches = BoincBatch::enum("app_id = $appid and state=$state order by id desc"); } else { $batches = BoincBatch::enum("state=$state order by id desc"); } fill_in_app_and_user_names($batches); show_batches_in_state($batches, $state); } } $user = get_logged_in_user(); $action = get_str('action', true); switch ($action) { case '': handle_main($user); break; case 'abort_batch': handle_abort_batch($user); break; case 'abort_batch_confirm': handle_abort_batch_confirm(); break; case 'admin': handle_admin($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; default: error_page("no such action $action"); } ?>