)
+// - logical name (how the science app refers to it)
+
+require_once('../inc/util.inc');
+require_once('../inc/sandbox.inc');
+require_once('../inc/submit_util.inc');
+
+display_errors();
+
+$buda_root = "../../buda_apps";
+
+// show list of BUDA apps and variants,
+// w/ buttons for adding and deleting
+//
+function app_list($notice=null) {
+ global $buda_root;
+ if (!is_dir($buda_root)) {
+ mkdir($buda_root);
+ }
+ page_head('Docker apps');
+ if ($notice) {
+ echo "$notice \n";
+ }
+ $dirs = scandir($buda_root);
+ foreach ($dirs as $dir) {
+ if ($dir[0] == '.') continue;
+ show_app($dir);
+ }
+ echo '
';
+ show_button_small('buda.php?action=app_form', 'Add app');
+ page_tail();
+}
+
+function show_app($dir) {
+ global $buda_root;
+ $indent = "    ";
+ echo "
$dir\n";
+ echo "$indent Variants (click for details):
';
+ echo $indent;
+ show_button_small("buda.php?action=variant_form&app=$dir", 'Add variant');
+ echo "";
+ echo "
";
+ show_button_small(
+ "buda.php?action=app_delete&app=$dir", "Delete app '$dir'"
+ );
+}
+
+function variant_view() {
+ global $buda_root;
+ $app = get_str('app');
+ $variant = get_str('variant');
+ page_head("App $app variant $variant");
+ $dir = "$buda_root/$app/$variant";
+ start_table();
+ table_header('name', 'size', 'md5');
+ foreach(scandir($dir) as $f) {
+ if ($f[0] == '.') continue;
+ [$size, $md5] = parse_info_file("$dir/.md5/$f");
+ table_row(
+ "$f",
+ $size,
+ $md5
+ );
+ }
+ end_table();
+ page_tail();
+}
+
+// form for creating app variant.
+// Currently doesn't support indirect files.
+// doing this would require checkboxes for indirect
+//
+// Could have other stuff like
+// - min_quorum, max_total_results
+// - rsc_disk_bound, rsc_memory_bound
+// or does this belong in job submission?
+//
+function variant_form($user) {
+ $sbitems = sandbox_select_items($user);
+ $app = get_str('app');
+
+ page_head("Create variant of Docker app $app");
+ form_start('buda.php');
+ form_input_hidden('app', $app);
+ form_input_hidden('action', 'variant_action');
+ form_input_text('Plan class', 'plan_class');
+ form_select('Dockerfile', 'dockerfile', $sbitems);
+ form_select('Main program', 'main_prog', $sbitems);
+ form_select_multiple('Other application files', 'others', $sbitems);
+ form_input_text('Input file names', 'input_file_names');
+ form_input_text('Output file names', 'output_file_names');
+ form_submit('OK');
+ form_end();
+ page_tail();
+}
+
+// copy file from sandbox to variant dir, and stage to download hier
+//
+function copy_and_stage_file($user, $fname, $dir, $variant) {
+ copy_sandbox_file($user, $fname, $dir);
+ [$md5, $size] = parse_info_file("$dir/.md5/$fname");
+ $phys_name = sprintf('buda_%s_%s_%s', $app, $variant, $md5);
+ stage_file_aux("$dir/$fname", $md5, $size, $phys_name);
+}
+
+// create variant
+//
+function variant_action($user) {
+ global $buda_root;
+ $plan_class = get_str('plan_class');
+ $app = get_str('app');
+ $dockerfile = get_str('dockerfile');
+ $main_prog = get_str('main_prog');
+ $others = get_array('others');
+ $input_file_names = explode(' ', get_str('input_file_names'));
+ $output_file_names = explode(' ', get_str('output_file_names'));
+
+ if (file_exists("$buda_root/$app/$plan_class")) {
+ error_page("Variant '$plan_class' already exists.");
+ }
+ $dir = "$buda_root/$app/$plan_class";
+ mkdir($dir);
+ mkdir("$dir/.md5");
+
+ // copy files from sandbox to variant dir
+ //
+ copy_and_stage_file($user, $dockerfile, $dir, $app, $variant);
+ copy_and_stage_file($user, $main_prog, $dir, $app, $variant);
+ foreach ($others as $fname) {
+ copy_and_stage_file($user, $fname, $dir, $app, $variant);
+ }
+
+ // create input template
+ //
+ $x = "\n";
+ $ninfiles = 2 + count($input_file_names) + count($others);
+ for ($i=0; $i<$ninfiles; $i++) {
+ $x .= " \n \n";
+ }
+ $x .= " \n";
+ $x .= file_ref_in('Dockerfile');
+ $x .= file_ref_in($main_prog);
+ foreach ($others as $fname) {
+ $x .= file_ref_in($fname);
+ }
+ foreach ($input_file_names as $fname) {
+ $x .= file_ref_in($fname);
+ }
+ $x .= " \n\n";
+ file_put_contents("$dir/template_in", $x);
+
+ // create output template
+ //
+ $x = "\n";
+ $i = 0;
+ foreach ($output_file_names as $fname) {
+ $x .= file_info_out($i++);
+ }
+ $x .= " \n";
+ $i = 0;
+ foreach ($output_file_names as $fname) {
+ $x .= file_ref_out($i++, $fname);
+ }
+ $x .= " \n\n";
+ file_put_contents("$dir/template_out", $x);
+
+ // Note: we don't currently allow indirect file access.
+ // If we did, we'd need to create job.toml to mount project dir
+
+ app_list("Variant $plan_class added for app $app.");
+}
+
+function file_ref_in($fname) {
+ return(sprintf(
+'
+ %s
+
+',
+ $fname
+ ));
+}
+function file_info_out($i) {
+ return sprintf(
+'
+
+
+
+ 5000000
+
+
+',
+ $i
+ );
+}
+
+function file_ref_out($i, $fname) {
+ return sprintf(
+'
+
+ %s
+
+', $i, $fname
+ );
+}
+
+function variant_delete() {
+ global $buda_root;
+ $app = get_str('app');
+ $variant = get_str('variant');
+ $confirmed = get_str('confirmed', true);
+ if ($confirmed) {
+ $dir = "$buda_root/$app/$variant";
+ // delete staged files
+ //
+ foreach (scandir("$dir/.md5") as $fname) {
+ if ($fname[0] == '.') continue;
+ [$size, $md5] = parse_file_info("$dir/$fname");
+ $phys_name = buda_app_file_phys_name($app, $variant, $md5);
+ $phys_path = download_path($phys_name);
+ unlink($phys_path);
+ }
+ system("rm -r $buda_root/$app/$variant", $ret);
+ if ($ret) {
+ error_page("delete failed");
+ }
+ $notice = "Variant $variant of app $app removed.";
+ app_list($notice);
+ } else {
+ page_head("Confirm");
+ echo "Are you sure want to delete variant $variant of app $app?
+
+ ";
+ show_button(
+ "buda.php?action=variant_delete&app=$app&variant=$variant&confirmed=yes",
+ "Yes"
+ );
+ page_tail();
+ }
+}
+
+function app_form() {
+ page_head("Create Docker app");
+ form_start();
+ form_input_text('Name', 'name');
+ form_submit('OK');
+ form_end();
+ page_tail();
+}
+
+function app_action() {
+ global $buda_root;
+ $name = get_str('name');
+ $dir = "$buda_root/$name";
+ if (file_exists($dir)) {
+ error_page("App $name already exists.");
+ }
+ mkdir($dir);
+ header("Location: buda.php");
+}
+
+function view_file() {
+ global $buda_root;
+ $app = get_str('app');
+ $variant = get_str('variant');
+ $fname = get_str('fname');
+ echo "
\n";
+ readfile("$buda_root/$app/$variant/$fname");
+}
+
+$user = get_logged_in_user();
+$action = get_str('action', true);
+switch ($action) {
+case 'app_form':
+ app_form(); break;
+case 'app_action':
+ app_action(); break;
+case 'app_delete':
+ app_delete(); break;
+case 'variant_view':
+ variant_view($user); break;
+case 'variant_form':
+ variant_form($user); break;
+case 'variant_action':
+ variant_action($user); break;
+case 'variant_delete':
+ variant_delete(); break;
+case 'view_file':
+ view_file(); break;
+case null:
+ app_list(); break;
+default:
+ error_page("unknown action $action");
+}
+
+?>
diff --git a/html/user/buda_submit.php b/html/user/buda_submit.php
new file mode 100644
index 0000000000..0dc2379a86
--- /dev/null
+++ b/html/user/buda_submit.php
@@ -0,0 +1,73 @@
+.
+
+// web interface for submitting BUDA jobs
+
+require_once('../inc/util.inc');
+require_once('../inc/sandbox.inc');
+
+display_errors();
+
+function submit_form($user) {
+ $sbitems_zip = sandbox_select_items($user, '/.zip$/');
+ if (!$sbitems_zip) {
+ error_page("No .zip files in your sandbox.");
+ }
+ $app = get_str('app');
+ $variant = get_str('variant');
+
+ page_head("Submit jobs to $app ($variant)");
+ form_start('buda_submit.php');
+ form_input_hidden('action', 'submit');
+ form_input_hidden('app', $app);
+ form_input_hidden('variant', $variant);
+ form_input_text('Batch name', 'batch_name');
+ form_select('Job file', 'job_file', $sbitems_zip);
+ form_submit('OK');
+ form_end();
+ page_tail();
+}
+
+function handle_submit() {
+ // stage app files if not already staged
+ //
+
+ // create batch
+ //
+
+ // unzip batch file
+ //
+
+ // stage top-level input files
+ //
+
+ // scan jobs; stage per-job input files and make create_work input
+ //
+
+ // create jobs
+}
+
+$user = get_logged_in_user();
+$action = get_str('action', true);
+if ($action == 'submit') {
+ handle_submit();
+} else {
+ submit_form($user);
+}
+
+?>
diff --git a/html/user/sandbox.php b/html/user/sandbox.php
index 1aecbda361..293606968c 100644
--- a/html/user/sandbox.php
+++ b/html/user/sandbox.php
@@ -16,14 +16,10 @@
// You should have received a copy of the GNU Lesser General Public License
// along with BOINC. If not, see .
-// Per-user "file sandboxes" for job submission.
-// These are stored in project-root/sandbox/USERID/
-//
-// The entries in a sandbox directory have contents
-// size md5
-//
-// The actual files are stored in the download hierarchy,
-// with sb_userid_MD5 as the physical name
+// Per-user "file sandboxes".
+// Files are stored in /sandbox//
+// File infos (md5/size) are scored in a parallel dir
+// /sandbox//.md5/
// NOTE: PHP's default max file upload size is 2MB.
// To increase this, edit /etc/php.ini, and change, e.g.
@@ -32,33 +28,31 @@
// post_max_size = 64M
require_once("../inc/sandbox.inc");
-require_once("../inc/submit_db.inc");
require_once("../inc/submit_util.inc");
display_errors();
function list_files($user, $notice) {
$dir = sandbox_dir($user);
- $d = opendir($dir);
- if (!$d) error_page("Can't open sandbox directory");
+ if (!is_dir($dir)) error_page("Can't open sandbox directory");
page_head("File sandbox");
if ($notice) {
echo "$notice
";
}
echo "
+
Upload files
+ 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 +60,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 +85,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 +100,48 @@ 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
+// 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";
}
diff --git a/tools/submit_buda b/tools/submit_buda
index 5b5950c3a7..add5f0abfb 100755
--- a/tools/submit_buda
+++ b/tools/submit_buda
@@ -1,35 +1,40 @@
#! /usr/bin/env php