diff --git a/checkin_notes b/checkin_notes index feff535114..d195a4abce 100644 --- a/checkin_notes +++ b/checkin_notes @@ -11092,3 +11092,16 @@ Charlie 16 Nov 2007 boinc.xcodeproj/ project.pbxproj BuildMacBOINC.sh + +David 16 Nov 2007 + - added optional code for user-submitted jobs (from M.F. Somers) + - added some scripts in ops/ for managing HR, and for blocking hosts. + (from M.F. Somers; these should be documented in the WIki + and perhaps added to ops/index.php) + + html/ + ops/ + hrclass_summary.php + reset_hrclass.php + block_host.php + queue/* diff --git a/html/ops/block_host.php b/html/ops/block_host.php new file mode 100644 index 0000000000..6046ecbced --- /dev/null +++ b/html/ops/block_host.php @@ -0,0 +1,34 @@ + 0) { + $result = mysql_query("UPDATE host SET max_results_day=1 WHERE id=".$hostid); +} + +echo $title; + +admin_page_tail(); + +?> diff --git a/html/ops/hrclass_summary.php b/html/ops/hrclass_summary.php new file mode 100644 index 0000000000..86a08264e3 --- /dev/null +++ b/html/ops/hrclass_summary.php @@ -0,0 +1,84 @@ +count; +} + +function make_reset_url( $hr_class ) { + return ("".$hr_class.""); +} + +db_init(); + +$timestr = time_str(time(0)); +$title = "hr_class summary list at ".$timestr; + +admin_page_head( $title ); + +start_table(); + +row4( "hr_class", "System", "CPU", "# unsent results" ); + +$unsentresults = get_mysql_count( 0 ); +row4( make_reset_url( 0 ), $system_string[ 128 ], $cpu_string[ 0 ], $unsentresults ); + +for( $system = 2; $system < 6; ++$system ) { + for( $cpu = 1; $cpu < 22; ++$cpu ) { + $hr_class=128*$system+$cpu; + + $unsentresults = get_mysql_count( $hr_class ); + + row4( make_reset_url( $hr_class ), $system_string[ $system * 128 ], $cpu_string[ $cpu ], $unsentresults ); + } +} + +end_table(); + +admin_page_tail(); + +?> diff --git a/html/ops/reset_hrclass.php b/html/ops/reset_hrclass.php new file mode 100644 index 0000000000..6007d0b1e1 --- /dev/null +++ b/html/ops/reset_hrclass.php @@ -0,0 +1,35 @@ + diff --git a/html/queue/README b/html/queue/README new file mode 100644 index 0000000000..810b9b4e59 --- /dev/null +++ b/html/queue/README @@ -0,0 +1,8 @@ +// This directory contains a system that allows +// users to submit jobs to a BOINC project. +// +// Major revisions may be required to make this work +// (and to make it secure) on your project. +// Please read and understand all the code before using it. +// +// Contributed by Dr. M.F. Somers, Leiden University diff --git a/html/queue/create_queue.sql b/html/queue/create_queue.sql new file mode 100644 index 0000000000..d6d02b83ee --- /dev/null +++ b/html/queue/create_queue.sql @@ -0,0 +1,20 @@ +CREATE TABLE q_list ( + id integer NOT NULL auto_increment, + user integer NOT NULL default '0', + workunit integer NOT NULL default '0', + PRIMARY KEY (id) +) TYPE=MyISAM; + +CREATE TABLE q_restricted_apps ( + id integer NOT NULL auto_increment, + appid integer NOT NULL default '0', + PRIMARY KEY (id) +) TYPE=MyISAM; + +CREATE TABLE q_users ( + id integer NOT NULL auto_increment, + user integer NOT NULL default '0', + app integer NOT NULL default '0', + qmax integer NOT NULL default '0', + PRIMARY KEY (id) +) TYPE=MyISAM; diff --git a/html/queue/inc/queue.inc b/html/queue/inc/queue.inc new file mode 100644 index 0000000000..d54cc76ad1 --- /dev/null +++ b/html/queue/inc/queue.inc @@ -0,0 +1,145 @@ + id ); + return $alljobs; +} + +function nr_of_jobs_of_user( $user ) +{ + $njobs = mysql_num_rows( all_jobs_of_user( $user ) ); + return $njobs; +} + +function workunit_name( $workunit ) +{ + if( ( $pos = strpos( $workunit -> name, "_queue" ) ) === false ) + $workunitname = $workunit -> name; + else + $workunitname = substr( $workunit -> name, 0, $pos ); + return $workunitname; +} + +function workunit_status_string( $workunit ) +{ + $status = "UNKNOWN"; + if( $workunit -> canonical_resultid ) + $status = "finished"; + else + { + if( $workunit -> hr_class ) + $status = "running"; + else + $status = "queued"; + } + if( $workunit -> error_mask ) + { + $status = "ERROR"; + if( $workunit -> error_mask & 16 ) + $status = "CANCELED"; + } + return $status; +} + +function max_nr_of_jobs_of_user( $user ) +{ + $allapps = mysql_query( "SELECT * FROM q_users WHERE user=".$user -> id ); + $napps = mysql_num_rows( $allapps ); + + if( $napps > 0 ) + for( $count = $index = 0; $index < $napps; ++$index ) + { + $row = mysql_fetch_object( $allapps ); + if( $row ) + $count += $row -> qmax; + } + else + $count = 5; + + mysql_free_result( $allapps ); + return $count; +} + +function nr_of_jobs_for_user_for_app( $user, $app ) +{ + $qmaxresult = mysql_query( "SELECT qmax FROM q_users WHERE user=".$user -> id." AND app=".$app -> id ); + if( mysql_num_rows( $qmaxresult ) < 1 ) + { + $qrestrictedapps = mysql_query( "SELECT * FROM q_restricted_apps WHERE appid=".$app -> id ); + if( mysql_num_rows( $qrestrictedapps ) < 1 ) + $nr = 5; + else + $nr = 0; + mysql_free_result( $qrestrictedapps ); + } + else + { + $object = mysql_fetch_object( $qmaxresult ); + $nr = $object -> qmax; + } + mysql_free_result( $qmaxresult ); + return $nr; +} + +function nr_of_submitted_jobs_for_user_for_app( $user, $app ) +{ + $alljobs = mysql_query( "SELECT * FROM q_list WHERE user=".$user -> id ); + $nrofjobs = mysql_num_rows( $alljobs ); + + for( $nr = $index = 0; $index < $nrofjobs; ++$index ) + { + $job = mysql_fetch_object( $alljobs ); + $workunit = mysql_fetch_object( mysql_query( "SELECT * FROM workunit WHERE id=".$job -> workunit ) ); + + if( $workunit -> appid == $app -> id ) + $nr = $nr + 1; + } + + mysql_free_result( $alljobs ); + return $nr; +} + +function exit_with_text( $text ) +{ + start_table(); + row1( "".$text."" ); + row1( "Commands" ); + row2( "", 'Go back to your queue' ); + row2( "", 'Log out' ); + end_table(); + page_tail(); + exit; +} + +function fan_out_dir( $filename, $fanoutnr ) +{ + $dir = dechex( hexdec( substr( md5( $filename ), 1, 7 ) ) % $fanoutnr ); + return $dir; +} + +function row5($xx, $xy, $yx, $yy, $zz ) { + echo "$xx$xy" + . "$yx$yy$zz + "; +} + +function row6($xx, $xy, $yx, $yy, $zz, $xz ) { + echo "$xx$xy" + . "$yx$yy$zz" + . "$xz"; +} + +function remove_tags( $xml, $tag ) +{ + $newxml = $xml; + while( ( $pos = strpos( $newxml, $tag ) ) !== false ) + $newxml = substr( $newxml, 0, $pos ).substr( $newxml, $pos + strlen( $tag ) ); + return $newxml; +} + +?> diff --git a/html/queue/inc/user.inc b/html/queue/inc/user.inc new file mode 100644 index 0000000000..57c5b16b17 --- /dev/null +++ b/html/queue/inc/user.inc @@ -0,0 +1,364 @@ +total_credit = 0.0; + $p->expavg_credit = 0.0; + while (!feof($f)) { + $buf = fgets($f); + if (strstr($buf, "")) break; + if ($x = parse_element($buf, "")) { + $p->name = $x; + } + if ($x = parse_element($buf, "")) { + $p->name = $x; + } + if ($x = parse_element($buf, "")) { + $p->url = $x; + } + if ($x = parse_element($buf, "")) { + $p->total_credit = $x; + } + if ($x = parse_element($buf, "")) { + $p->expavg_credit = $x; + } + if ($x = parse_element($buf, "")) { + $p->id = $x; + } + if ($x = parse_element($buf, "")) { + $p->country = $x; + } + if ($x = parse_element($buf, "")) { + $p->team_id = $x; + } + if ($x = parse_element($buf, "")) { + $p->team_name = $x; + } + if ($x = parse_element($buf, "")) { + $p->create_time = $x; + } + } + return $p; +} + +function parse_user($f, $user) { + $user->projects = array(); + while (!feof($f)) { + $buf = fgets($f); + if (strstr($buf, "")) break; + if (strstr($buf, "")) { + $user->projects[] = parse_project($f); + } + } + return $user; +} + +function get_other_projects($user) { + $cpid = md5($user->cross_project_id . $user->email_addr); + $url = "http://boinc.netsoft-online.com/get_user.php?cpid=$cpid"; + $f = fopen($url, "r"); + if (!$f) { + return $user; + } + $u = parse_user($f, $user); + fclose($f); + return $u; +} + +function show_project($project) { + if ($project->url == "http://www.worldcommunitygrid.org/") { + $x = $project->name; + } else { + $x = "url"."show_user.php?userid=$project->id\">$project->name"; + } + echo " + $x + ".number_format($project->total_credit, 0)." + ".number_format($project->expavg_credit, 0)." + ".date_str($project->create_time)." + + "; +} + +function cmp($a, $b) { + if ($a->expavg_credit == $b->expavg_credit) return 0; + return ($a->expavg_credit < $b->expavg_credit)? 1 : -1; +} + +function show_other_projects($user, $personal) { + if (count($user->projects) > 1) { + usort($user->projects, "cmp"); + if ($personal) { + echo "

Projects in which you are participating

"; + } else { + echo "

Projects in which $user->name is participating

"; + } + start_table(); + row_heading_array(array( + "Project
Click for user page", "Total credit", "Average credit", "Since" + )); + foreach($user->projects as $project) { + show_project($project); + } + end_table(); + } +} + +function pending_credit($user) { + $result = mysql_query("select sum(claimed_credit) as total from result where userid=$user->id and (validate_state=0 or validate_state=4)"); + $foobar = mysql_fetch_object($result); + if (!$foobar) return 0; + mysql_free_result($result); + return $foobar->total; +} + +function total_posts($user) { + $result = mysql_query( + "select count(id) as total from post where user=$user->id" + ); + if (!$result) return 0; + $foobar = mysql_fetch_object($result); + mysql_free_result($result); + return $foobar->total; +} + +function show_credit($user) { + row2(tr(TOTAL_CREDIT), format_credit($user->total_credit)); + row2(tr(EXPAVG_CREDIT), format_credit($user->expavg_credit)); + project_user_credit($user); +} + +require_once("../inc/stats_sites.inc"); +// show dynamic user info (private) +// +function show_user_stats_private($user) { + global $cpid_stats_sites; + row1("Work done"); + row2(PROJECT." member since", date_str($user->create_time)); + show_credit($user); + $config = get_config(); + if (parse_bool($config, "show_results")) { + row2("Pending credit", "View"); + } + row2("Computers on this account", + "View" + ); + row2("Results", "id>View"); + $cpid = md5($user->cross_project_id . $user->email_addr); + $x = ""; + shuffle($cpid_stats_sites); + foreach ($cpid_stats_sites as $site) { + $name = $site[0]; + $y = sprintf($site[1], $cpid); + $x .= "$name
"; + } + $x .= "
Cross-project ID: $cpid\n"; + row2("Cross-project statistics", $x); + row2("Stats on your cell phone", URL_BASE."userw.php?id=$user->id"); + row2("Account number
Used in URLs", $user->id); +} + +// show static user info (private) +// +function show_user_info_private($user) { + if (is_valid_email_addr($user->email_addr)) { + $email_text = $user->email_addr; + } else { + $email_text = "Verification pending"; + } + + row1("Account information"); + row2("Email address
", $email_text); + row2("Name", $user->name); + if (strlen($user->url)) { + $x = "http://$user->url"; + } else { + $x = "none"; + } + row2("URL", $x); + row2("Country", $user->country); + row2("Postal code", $user->postal_code); + row2("Change", "email address | password | other account info"); + row2("", "Show private queue"); + row2("", "authenticator).">Log out"); + + row1("Community"); + + $sql = "SELECT * FROM profile WHERE userid = ".$user->id; + $result = mysql_query($sql); + if (mysql_num_rows($result) != 0) { + $x = "id>View or edit | Delete"; + } else { + $x = "Create"; + } + row2("Profile", $x); + $tot = total_posts($user); + if ($tot) { + row2("Message boards", "id>$tot posts"); + } + + row2("Private messages", pm_notification($user)); + + row1("Teams"); + if ($user->teamid) { + $team = lookup_team($user->teamid); + $x = "id>$team->name + | Quit team"; + if ($team->userid == $user->id) { + $x .= " | management functions"; + } + row2("Team", $x); + } else { + row2("Team", "None (find a team)"); + } + + $team_founder = lookup_team_founder($user->id); + if ($team_founder) { + while ($res = mysql_fetch_object($team_founder)) { + if ($res->id != $user->teamid) { + row2("founder of", "id>$res->name | id."\">Change team founder"); + } + } + } + + row1("Preferences"); + row2( + "General preferences
specify when and how BOINC uses your computer", + "
View or edit" + ); + row2(PROJECT." preferences
control resource share and customize graphics", + "View or edit" + ); + row2("Message board preferences
configure features and appearance of message boards", + "View or edit" + ); +} + +// show summary of dynamic and static info (public) +// +function show_user_summary_public($user) { + row2(PROJECT." member since", date_str($user->create_time)); + row2("Country", $user->country); + if (strlen($user->url)) { + row2("URL", "url\">http://$user->url"); + } + show_credit($user); + + if ($user->teamid && ($team = lookup_team($user->teamid))) { + row2("Team", "id\">$team->name"); + } else { + row2("Team", "None"); + } + if ($user->show_hosts) { + row2("Computers", "id\">View"); + } else { + row2("Computers", "hidden"); + } + $tot = total_posts($user); + if ($tot) { + row2("Message boards", "id\">$tot posts"); + } + + if ($user->donated == 1) { + if (file_exists("../project/donations.inc")) { + require_once("../project/donations.inc"); + $x .= DONATION_LINK; + row2("Donor",$x); + } + } + + row2("Contact", "id."\">Send private message"); +} + +function show_profile_link($user) { + if ($user->has_profile) { + row2("Profile", "id\">View"); + } +} + +// show a summary of the user. +// NOTE: This is intended to be shown only to that user. +// it has info that other users aren't supposed to see + +function show_user_page_private($user) { + $config = get_config(); + start_table("width=100%"); + show_user_info_private($user); + show_user_stats_private($user); + + // Does this project accept donations? Then put in a project specific + // function to show user donation information in ../project/donations.inc + // + if (parse_bool($config, "donations_accepted")) { + if (file_exists("../project/donations.inc")) { + require_once("../project/donations.inc"); + show_user_donations_private($user); + } + } + end_table(); +} + +function user_table_start($sort_by) { + start_table(); + echo " + + ".tr(USER_TABLE_RANK)." + ".tr(USER_TABLE_NAME)." + "; + if ($sort_by == "total_credit") { + echo " + ".tr(EXPAVG_CREDIT)." + ".tr(TOTAL_CREDIT)." + "; + } else { + echo " + ".tr(EXPAVG_CREDIT)." + ".tr(TOTAL_CREDIT)." + "; + } + echo " + ".tr(USER_TABLE_COUNTRY)." + ".tr(USER_TABLE_PTIME)." + + "; +} + +function show_user_row($user, $i) { + echo " + + $i + ", user_links($user), " + ", format_credit($user->expavg_credit), " + ", format_credit($user->total_credit), " + ", $user->country, " + ", time_str($user->create_time)," + + "; +} + +// decay a user's average credit +// +function user_decay_credit($user) { + $avg = $user->expavg_credit; + $avg_time = $user->expavg_time; + $now = time(0); + update_average($now, 0, 0, $avg, $avg_time); + mysql_query("update user set expavg_credit=$avg, expavg_time=$now where id=$user->id"); + +} +// if the user hasn't received new credit for ndays, +// decay its average and return true +// +function user_inactive_ndays($user, $ndays) { + $diff = time() - $user->expavg_time; + if ($diff > $ndays*86400) { + user_decay_credit($user); + return true; + } + return false; +} + +?> diff --git a/html/queue/ops/ops_queue_remove_job.php b/html/queue/ops/ops_queue_remove_job.php new file mode 100644 index 0000000000..9d85cb6374 --- /dev/null +++ b/html/queue/ops/ops_queue_remove_job.php @@ -0,0 +1,67 @@ +id ) ); +$user = mysql_fetch_object( mysql_query( "SELECT * FROM user WHERE id=".$job -> user ) ); +$title = "Deleting job '".workunit_name( $workunit )."' (".$workunitid.") of ".$user -> name." at ".$timestr; + +$jobname = workunit_name( $workunit ); + +$config = get_config(); + +$jobstatusstring = workunit_status_string( $workunit ); +$jobsubmittime = time_str( $workunit -> create_time ); + +admin_page_head( $title ); +start_table(); +row1( "Job speciffics" ); +row2( "Job submit time: ", $jobsubmittime ); +row2( "Job name: ", $jobname ); +row2( "Old job status: ", $jobstatusstring ); + +$allresults = mysql_query( "SELECT * FROM result WHERE workunitid=".$workunitid ); +$nrofresults = mysql_num_rows( $allresults ); + +for( $resultindex = 0; $resultindex < $nrofresults; ++$resultindex ) +{ + $result = mysql_fetch_object( $allresults ); + $result -> xml_doc_in = remove_tags( $result -> xml_doc_in, "" ); + $query = "UPDATE result SET xml_doc_in='".$result -> xml_doc_in."' WHERE id=".$result -> id; + mysql_query( $query ); +} + +$query = "UPDATE result SET server_state=5,outcome=5 WHERE server_state=2 AND workunitid=".$workunit -> id; +mysql_query( $query ); + +$workunit -> xml_doc = remove_tags( $workunit -> xml_doc, "" ); +$query = "UPDATE workunit SET xml_doc='".$workunit -> xml_doc."' WHERE id=".$workunit -> id; +mysql_query( $query ); + +$query = "UPDATE workunit SET error_mask=error_mask|16,transition_time=".time(0)." WHERE id=".$workunit -> id; +mysql_query( $query ); + +$query = "DELETE FROM q_list WHERE id=".$job -> id; +mysql_query( $query ); + +row2( "New job status: ", "deleted" ); + +row1( "Commands" ); +row2( "", 'Go back to queue' ); + +end_table(); +admin_page_tail(); + +?> diff --git a/html/queue/ops/ops_queue_show_job.php b/html/queue/ops/ops_queue_show_job.php new file mode 100644 index 0000000000..57201f30b6 --- /dev/null +++ b/html/queue/ops/ops_queue_show_job.php @@ -0,0 +1,126 @@ +id ) ); +$user = mysql_fetch_object( mysql_query( "SELECT * FROM user WHERE id=".$job -> user ) ); +$title = "Job '".workunit_name( $workunit )."' (".$workunitid.") of ".$user -> name." at ".$timestr; + +$jobname = workunit_name( $workunit ); + +$config = get_config(); + +$jobapplication = mysql_fetch_object( mysql_query( "SELECT * FROM app WHERE id=".$workunit -> appid ) ); +$jobapplicationname = $jobapplication -> name; +$jobapplicationfriendlyname = $jobapplication -> user_friendly_name; +$jobfops = $workunit -> rsc_fpops_est; +$jobmem = $workunit -> rsc_memory_bound; +$jobdisk = $workunit -> rsc_disk_bound; +$jobstatusstring = workunit_status_string( $workunit ); + +$coloredjobstatusstring = $jobstatusstring; +if( $jobstatusstring == "running" ) $coloredjobstatusstring = "".$jobstatusstring.""; +if( $jobstatusstring == "queued" ) $coloredjobstatusstring = "".$jobstatusstring.""; +if( $jobstatusstring == "ERROR" ) $coloredjobstatusstring = "".$jobstatusstring.""; + +$jobsubmittime = time_str( $workunit -> create_time ); + +$workunitidstring = " workunit.">".$job -> workunit.""; + +$jobinputurl = parse_element( $workunit -> xml_doc, "" ); +$jobinputurl = parse_element( $jobinputurl, "" ); +$jobinput = parse_element( $workunit -> xml_doc, "" ); +$jobinput = parse_element( $jobinput, "" ); + +admin_page_head( $title ); +start_table(); + +row1( "Job speciffics" ); +row2( "Job status: ", $coloredjobstatusstring ); +row2( "Job application: ", $jobapplicationfriendlyname ); +row2( "Job submit time: ", $jobsubmittime ); +row2( "Job name: ", $jobname ); +row2( "Job id: ", $workunitidstring ); +row2( "Job estimated time to complete: ", floor((float)($jobfops)/92254963740)." min. " ); +row2( "Job estimated memory usage: ", floor((float)($jobmem)/1048576)." Mb. " ); +row2( "Job estimated disk usage: ", floor((float)($jobdisk)/1048576)." Mb. " ); +row2( "Job input file:", ' '.$jobinput.'' ); + +if( ( $jobstatusstring == "finished" ) || ( $jobstatusstring == "ERROR" ) ) +{ + if( $jobstatusstring != "finished" ) + { + $resultunitquery = mysql_query( "SELECT * FROM result WHERE workunitid=".$workunit -> id ); + $nrofresults = mysql_num_rows( $resultunitquery ); + + for( $index = 0; $index < $nrofresults; ++$index ) + { + $resultunit = mysql_fetch_object( $resultunitquery ); + + $jobstderr = parse_element( $resultunit -> stderr_out, "" ); + + if( $jobstderr ) + { + row1( "Error output of this job" ); + row2( "", $jobstderr ); + } + } + } + else + { + $resultunit = mysql_fetch_object( mysql_query( "SELECT * FROM result WHERE id=".$workunit -> canonical_resultid ) ); + + $xmldoc = $resultunit -> xml_doc_out; + + $nroffiles = 0; + $cursor = 0; + while( $tempfileinfo = parse_next_element( $xmldoc, "", &$cursor ) ) + $outputfiles[ $nroffiles++ ] = parse_element( $tempfileinfo, "" ); + + if( $nroffiles >= 1 ) + { + $fanoutnr = parse_config( $config, "" ); + row1( "Output of this job" ); + row2( "Number of output files of job: ", $nroffiles ); + for( $index = 0; $index < $nroffiles; ++$index ) + { + $filename = $outputfiles[ $index ]; + $url = "upload/".fan_out_dir( $filename, $fanoutnr )."/".$filename; + $outputfilelink = ''.$filename.''; + row2( "Output file ".($index+1).": ", $outputfilelink ); + } + } + + $jobstderr = parse_element( $resultunit -> stderr_out, "" ); + + if( $jobstderr ) + { + row1( "Error output of this job" ); + row2( "", $jobstderr ); + } + } +} + +$max_jobs = max_nr_of_jobs_of_user( $user ); +$njobs = nr_of_jobs_of_user( $user ); + +row1( "Commands" ); +row2( "", 'Kill or Remove this job' ); +row2( "", 'Go back to queue' ); + +end_table(); + +admin_page_tail(); +?> diff --git a/html/queue/ops/ops_queue_show_queue.php b/html/queue/ops/ops_queue_show_queue.php new file mode 100644 index 0000000000..8f35d4dd16 --- /dev/null +++ b/html/queue/ops/ops_queue_show_queue.php @@ -0,0 +1,71 @@ + 1 ) + row1( "There are ".$njobs." jobs listed !
" ); + else + row1( "There is only one job listed !
" ); + + end_table(); + start_table(); + + row6( "Job #", "User", "Job submit time", "Job status", "Job name", "Job ID" ); + + for( $jobindex = 0; $jobindex < $njobs; ++$jobindex ) + { + $workunit = mysql_fetch_object( $alljobs ); + + $prefix = ''; + $workunitname = $prefix.workunit_name( $workunit ).''; + $workunitidstr = "".$workunit -> id.""; + $status = workunit_status_string( $workunit ); + $jobsubmittime = time_str( $workunit -> create_time ); + + if( $status != "CANCELED" ) + { + if( $status == "running" ) $status = "".$status.""; + if( $status == "queued" ) $status = "".$status.""; + + $job = mysql_fetch_object( mysql_query( "SELECT * FROM q_list WHERE workunit=".$workunit->id ) ); + $user = mysql_fetch_object( mysql_query( "SELECT * FROM user WHERE id=".$job -> user ) ); + $jobusername = "".$user -> name.""; + } + else + { + $jobusername = "UNKNOWN"; + $status = "CANCELED"; + $workunitname = workunit_name( $workunit ); + } + + row6( $jobindex+1, $jobusername, $jobsubmittime, $status, $workunitname, $workunitidstr ); + } + +} +else + row1("There are NO jobs listed !
"); + +end_table(); + +admin_page_tail(); + +?> diff --git a/html/queue/user/queue_new_job_form.php b/html/queue/user/queue_new_job_form.php new file mode 100644 index 0000000000..36d658516b --- /dev/null +++ b/html/queue/user/queue_new_job_form.php @@ -0,0 +1,90 @@ + name." at ".$timestr; + +page_head( $title ); + +$appresult = mysql_query( "SELECT * FROM app" ); +$nrofapps = mysql_num_rows( $appresult ); + +if( $nrofapps ) +{ + + $selection = ""; + for( $appindex = 0; $appindex < $nrofapps; ++$appindex ) + { + $app = mysql_fetch_object( $appresult ); + + $appqmax = nr_of_jobs_for_user_for_app( $user, $app ); + $appsubmitted = nr_of_submitted_jobs_for_user_for_app( $user, $app ); + + if( $appqmax > $appsubmitted ) + $selection = $selection.''; + } + + if( $selection != "" ) + { + + echo '
'; + start_table(); + + row1( "New job speciffics" ); + $selection = ""; + row2( "Application: ", $selection ); + row2( "Name of job (no spaces, quotes or slashes): ", '' ); + row2( "Input: ", '' ); + + $selection = ''; + $selection .= ''; + $selection .= ''; + $selection .= ''; + $selection .= ''; + $selection .= ''; + $selection = ""; + row2( "Estimated time to completion: ", $selection ); + + $selection = ''; + $selection .= ''; + $selection .= ''; + $selection .= ''; + $selection .= ''; + $selection = ""; + row2( "Estimated memory usage: ", $selection ); + + $selection = ''; + $selection .= ''; + $selection .= ''; + $selection .= ''; + $selection .= ''; + $selection .= ''; + $selection = ""; + row2( "Estimated disk usage: ", $selection ); + + row2( "", '' ); + + row1( "Commands" ); + row2( "", 'Run Classical-Builder' ); + row2( "", 'Go back to your queue' ); + row2( "", 'Log out' ); + + end_table(); + echo '
'; + + } + else + exit_with_text( "You are not allowed to submit any jobs !" ); + +} + +page_tail(); + +?> diff --git a/html/queue/user/queue_new_job_form_action.php b/html/queue/user/queue_new_job_form_action.php new file mode 100644 index 0000000000..9b0345c1e1 --- /dev/null +++ b/html/queue/user/queue_new_job_form_action.php @@ -0,0 +1,154 @@ +" ); +$user = get_logged_in_user(); + +$jobapplicationname = mysql_fetch_object( mysql_query( "SELECT * FROM app WHERE id=".$jobapplication ) ); +$app = $jobapplicationname; +$jobapplicationfriendlyname = $jobapplicationname -> user_friendly_name; +$jobapplicationname = $jobapplicationname -> name; + +$title = "New job for '".$jobname."' ".$user -> name." at ".$timestr; +page_head( $title ); + +start_table(); +row1( "Job speciffics" ); +row2( "Job application: ", $jobapplicationfriendlyname ); +row2( "Job name: ", $jobname ); +row2( "Job estimated time to complete: ", floor( ( float )( $jobfops ) / 92254963740 )." min. " ); +row2( "Job estimated memory usage: ", floor( ( float )( $jobmem ) / 1048576 )." Mb. " ); +row2( "Job estimated disk usage: ", floor( ( float )( $jobdisk ) / 1048576 )." Mb. " ); +row2( "Job input:", '' ); +end_table(); + +if( ( $jobname == "" ) || strpos( $jobname, "queue" ) || strpos( $jobname, " " ) || + strpos( $jobname, '"' ) || strpos( $jobname, "'" ) || strpos( $jobname, "`" ) || + strpos( $jobname, "\\" ) ) + exit_with_text( "The job name is invalid !" ); + +if( $jobinput == "" ) + exit_with_text( "There was no input !" ); + +$appqmax = nr_of_jobs_for_user_for_app( $user, $app ); +$appsubmitted = nr_of_submitted_jobs_for_user_for_app( $user, $app ); +if( $appqmax <= $appsubmitted ) + exit_with_text( "Job limit would be exceeded!" ); + +$bin_dir = parse_config( $config, "" ); +$download_dir = parse_config( $config, "" ); +$upload_dir = parse_config( $config, "" ); +$template_dir = parse_config( $config, "" ); +$config_dir = parse_config( $config, "" ); +$createworkprogram = parse_config( $config, "" ); + +$extendedjobname = $jobname."_queue_".$jobapplication."_".time(0)."_".random_string(); +$extendedjobname = escapeshellcmd( $extendedjobname ); + +$wu_template = $template_dir."/queue_".$jobapplicationname."_work_unit_template"; +$result_template = $template_dir."/queue_".$jobapplicationname."_result_unit_template"; +$temporaryinputfile = $extendedjobname; + +$command_to_submit = $bin_dir."/".$createworkprogram; +$command_to_submit .= " -config_dir ".$config_dir; +$command_to_submit .= " -appname ".$jobapplicationname; +$command_to_submit .= " -wu_name ".$extendedjobname; +$command_to_submit .= " -wu_template ".$wu_template; +$command_to_submit .= " -result_template ".$result_template; +$command_to_submit .= " -rsc_fpops_est ".floor( ( float )( $jobfops ) ); +$command_to_submit .= " -rsc_fpops_bound ".floor( 3.0 * ( float )( $jobfops ) ); +$command_to_submit .= " -rsc_memory_bound ".floor( ( float )( $jobmem ) ); +$command_to_submit .= " -rsc_disk_bound ".floor( ( float )( $jobdisk ) ); +$command_to_submit .= " -priority 10 -batch ".$user -> id; +$command_to_submit .= " ".$temporaryinputfile; +$command_to_submit = escapeshellcmd( $command_to_submit ); +$command_to_submit = "cd ".$config_dir."; ".$command_to_submit; + +$temporaryinputfile = $download_dir."/".$temporaryinputfile; + +$filehandle = fopen( $temporaryinputfile, "w" ); +if( !$filehandle ) + exit_with_text( "Cannot create the temporary input file !" ); + +if( !fwrite( $filehandle, $jobinput ) ) +{ + fclose( $filehandle ); + exit_with_text( "Cannot write to the temporary input file !" ); +} + +fclose( $filehandle ); + +if( strpos( $jobapplicationname, "classical" ) !== false ) +{ + $testinputcommand = $bin_dir."/verify_classical_input ".$temporaryinputfile." /dev/null /dev/stdout /dev/stdout"; + $testinputcommand = escapeshellcmd( $testinputcommand ); + $testinputcommand = "cd ".$config_dir."; ".$testinputcommand; + $errorline = 0; + exec( $testinputcommand, &$outputoftest, &$errorline ); + if( $errorline != 0 ) + { + $errorstring = "Your input had an error on line ".$errorline." ! The job was not submitted !"; + unlink( $temporaryinputfile ); + exit_with_text( $errorstring ); + } +} + +system( $command_to_submit ); + +unlink( $temporaryinputfile ); + +$workunit = mysql_fetch_object( mysql_query( "SELECT * FROM workunit WHERE name='".$extendedjobname."'" ) ); + +if( !$workunit ) + exit_with_text( "Error during submition of the workunit associated with your job !" ); + +$qlistentry = mysql_query( "INSERT INTO q_list VALUES('','".$user->id."','".$workunit->id."')" ); + +if( !$qlistentry ) + exit_with_text( "Error during submition of your job !" ); + +$jobidlink = ''.$jobname.' ('.$workunit -> id.')'; + +start_table(); +row1( "Your job has been submitted !" ); +row2( "Job status: ", workunit_status_string( $workunit ) ); +row2( "Job id: ", $jobidlink ); + +row1( "Commands" ); +row2( "Status of this job: ", 'Show job status' ); +$max_jobs = max_nr_of_jobs_of_user( $user ); +$njobs = nr_of_jobs_of_user( $user ); +if( $njobs < $max_jobs ) +{ + if( $max_jobs - $njobs > 1 ) + $line = "You can submit ".($max_jobs-$njobs)." more jobs: "; + else + $line = "You can submit one more job: "; + row2( $line, 'Submit another job' ); +} +row2( "", 'Go back to your queue' ); +row2( "", 'Log out' ); + +end_table(); +page_tail(); + +?> diff --git a/html/queue/user/queue_remove_job.php b/html/queue/user/queue_remove_job.php new file mode 100644 index 0000000000..45c9e6b008 --- /dev/null +++ b/html/queue/user/queue_remove_job.php @@ -0,0 +1,82 @@ + name." at ".$timestr; + +$jobname = workunit_name( $workunit ); + +if( $user -> id != $job -> user ) +{ + $title = "Job '".$jobname."' (".$workunitid.")"; + page_head( $title ); + exit_with_text( "You are not the owner of this job !" ); +} + +$config = get_config(); + +$jobstatusstring = workunit_status_string( $workunit ); +$jobsubmittime = time_str( $workunit -> create_time ); + +page_head( $title ); +start_table(); +row1( "Job speciffics" ); +row2( "Job submit time: ", $jobsubmittime ); +row2( "Job name: ", $jobname ); +row2( "Old job status: ", $jobstatusstring ); + +$allresults = mysql_query( "SELECT * FROM result WHERE workunitid=".$workunitid ); +$nrofresults = mysql_num_rows( $allresults ); + +for( $resultindex = 0; $resultindex < $nrofresults; ++$resultindex ) +{ + $result = mysql_fetch_object( $allresults ); + $result -> xml_doc_in = remove_tags( $result -> xml_doc_in, "" ); + $query = "UPDATE result SET xml_doc_in='".$result -> xml_doc_in."' WHERE id=".$result -> id; + mysql_query( $query ); +} + +$query = "UPDATE result SET server_state=5,outcome=5 WHERE server_state=2 AND workunitid=".$workunit -> id; +mysql_query( $query ); + +$workunit -> xml_doc = remove_tags( $workunit -> xml_doc, "" ); +$query = "UPDATE workunit SET xml_doc='".$workunit -> xml_doc."' WHERE id=".$workunit -> id; +mysql_query( $query ); + +$query = "UPDATE workunit SET error_mask=error_mask|16,transition_time=".time(0)." WHERE id=".$workunit -> id; +mysql_query( $query ); + +$query = "DELETE FROM q_list WHERE id=".$job -> id; +mysql_query( $query ); + +row2( "New job status: ", "deleted" ); + +$max_jobs = max_nr_of_jobs_of_user( $user ); +$njobs = nr_of_jobs_of_user( $user ); + +row1( "Commands" ); +if( $njobs < $max_jobs ) +{ + if( $max_jobs - $njobs > 1 ) + $line = "You can submit ".($max_jobs-$njobs)." more jobs: "; + else + $line = "You can submit one more job: "; + row2( $line, 'Submit a job' ); +} +row2( "", 'Go back to your queue' ); +row2( "", 'Log out' ); + +end_table(); + +?> diff --git a/html/queue/user/queue_show_job.php b/html/queue/user/queue_show_job.php new file mode 100644 index 0000000000..fd79194513 --- /dev/null +++ b/html/queue/user/queue_show_job.php @@ -0,0 +1,138 @@ + name." at ".$timestr; + +$jobname = workunit_name( $workunit ); + +if( $user -> id != $job -> user ) +{ + $title = "Job '".$jobname."' (".$workunitid.")"; + page_head( $title ); + exit_with_text( "You are not the owner of this job !" ); +} + +$config = get_config(); + +$jobapplication = mysql_fetch_object( mysql_query( "SELECT * FROM app WHERE id=".$workunit -> appid ) ); +$jobapplicationname = $jobapplication -> name; +$jobapplicationfriendlyname = $jobapplication -> user_friendly_name; +$jobfops = $workunit -> rsc_fpops_est; +$jobmem = $workunit -> rsc_memory_bound; +$jobdisk = $workunit -> rsc_disk_bound; +$jobstatusstring = workunit_status_string( $workunit ); + +$coloredjobstatusstring = $jobstatusstring; +if( $jobstatusstring == "running" ) $coloredjobstatusstring = "".$jobstatusstring.""; +if( $jobstatusstring == "queued" ) $coloredjobstatusstring = "".$jobstatusstring.""; +if( $jobstatusstring == "ERROR" ) $coloredjobstatusstring = "".$jobstatusstring.""; + +$jobsubmittime = time_str( $workunit -> create_time ); + +$workunitidstring = " workunit.">".$job -> workunit.""; + +$jobinputurl = parse_element( $workunit -> xml_doc, "" ); +$jobinputurl = parse_element( $jobinputurl, "" ); +$jobinput = parse_element( $workunit -> xml_doc, "" ); +$jobinput = parse_element( $jobinput, "" ); + +page_head( $title ); +start_table(); + +row1( "Job speciffics" ); +row2( "Job status: ", $coloredjobstatusstring ); +row2( "Job application: ", $jobapplicationfriendlyname ); +row2( "Job submit time: ", $jobsubmittime ); +row2( "Job name: ", $jobname ); +row2( "Job id: ", $workunitidstring ); +row2( "Job estimated time to complete: ", floor((float)($jobfops)/92254963740)." min. " ); +row2( "Job estimated memory usage: ", floor((float)($jobmem)/1048576)." Mb. " ); +row2( "Job estimated disk usage: ", floor((float)($jobdisk)/1048576)." Mb. " ); +row2( "Job input file:", ' '.$jobinput.'' ); + +if( ( $jobstatusstring == "finished" ) || ( $jobstatusstring == "ERROR" ) ) +{ + if( $jobstatusstring != "finished" ) + { + $resultunitquery = mysql_query( "SELECT * FROM result WHERE workunitid=".$workunit -> id ); + $nrofresults = mysql_num_rows( $resultunitquery ); + + for( $index = 0; $index < $nrofresults; ++$index ) + { + $resultunit = mysql_fetch_object( $resultunitquery ); + + $jobstderr = parse_element( $resultunit -> stderr_out, "" ); + + if( $jobstderr ) + { + row1( "Error output of this job" ); + row2( "", $jobstderr ); + } + } + } + else + { + $resultunit = mysql_fetch_object( mysql_query( "SELECT * FROM result WHERE id=".$workunit -> canonical_resultid ) ); + + $xmldoc = $resultunit -> xml_doc_out; + $jobstderr = parse_element( $resultunit -> stderr_out, "" ); + + $nroffiles = 0; + $cursor = 0; + while( $tempfileinfo = parse_next_element( $xmldoc, "", &$cursor ) ) + $outputfiles[ $nroffiles++ ] = parse_element( $tempfileinfo, "" ); + + if( $nroffiles >= 1 ) + { + $fanoutnr = parse_config( $config, "" ); + row1( "Output of this job" ); + row2( "Number of output files of job: ", $nroffiles ); + for( $index = 0; $index < $nroffiles; ++$index ) + { + $filename = $outputfiles[ $index ]; + $url = "upload/".fan_out_dir( $filename, $fanoutnr )."/".$filename; + $outputfilelink = ''.$filename.''; + row2( "Output file ".($index+1).": ", $outputfilelink ); + } + } + + if( $jobstderr ) + { + row1( "Error output of this job" ); + row2( "", $jobstderr ); + } + } +} + +$max_jobs = max_nr_of_jobs_of_user( $user ); +$njobs = nr_of_jobs_of_user( $user ); + +row1( "Commands" ); +if( $njobs < $max_jobs ) +{ + if( $max_jobs - $njobs > 1 ) + $line = "You can submit ".($max_jobs-$njobs)." more jobs: "; + else + $line = "You can submit one more job: "; + row2( $line, 'Submit a job' ); +} +row2( "", 'Kill or Remove this job' ); +row2( "", 'Go back to your queue' ); +row2( "", 'Log out' ); + +end_table(); + +page_tail(); +?> diff --git a/html/queue/user/queue_show_queue.php b/html/queue/user/queue_show_queue.php new file mode 100644 index 0000000000..af2211031c --- /dev/null +++ b/html/queue/user/queue_show_queue.php @@ -0,0 +1,93 @@ + name." at ".$timestr; + +page_head( $title ); + +$alljobs = all_jobs_of_user( $user ); +$njobs = mysql_num_rows( $alljobs ); + +start_table(); + +if( $njobs ) +{ + if( $njobs > 1 ) + row1( "You have ".$njobs." jobs listed !
" ); + else + row1( "You have ".$njobs." job listed !
" ); + + end_table(); + start_table(); + + row5( "Job #", "Job submit time", "Job status", "Job name", "Job ID" ); + + for( $jobindex = 0; $jobindex < $njobs; ++$jobindex ) + { + $job = mysql_fetch_object( $alljobs ); + + $workunitquery = mysql_query( "SELECT * FROM workunit WHERE id=".$job -> workunit ); + if( $workunitquery ) + { + $workunit = mysql_fetch_object( $workunitquery ); + + if( $workunit ) + { + $prefix = ''; + $workunitname = $prefix.workunit_name( $workunit ).''; + $status = workunit_status_string( $workunit ); + if( $status == "running" ) $status = "".$status.""; + if( $status == "queued" ) $status = "".$status.""; + if( $status == "ERROR" ) $status = "".$status.""; + $jobsubmittime = time_str( $workunit -> create_time ); + } + else + { + $workunitname = "WORKUNIT NOT FOUND IN DATABASE"; + $status = "UNKNOWN"; + $jobsubmittime = "UNKNOWN"; + } + + mysql_free_result( $workunitquery ); + } + + $workunitstring = " workunit.">".$job -> workunit.""; + row5( $jobindex+1, $jobsubmittime, $status, $workunitname, $workunitstring ); + } + +} +else + row1("You have NO jobs listed !
"); + +end_table(); + +$max_jobs = max_nr_of_jobs_of_user( $user ); + +if( $max_jobs > $njobs ) +{ + if( $max_jobs - $njobs > 1 ) + $line = 'You can submit '.( $max_jobs - $njobs ).' more jobs: '; + else + $line = 'You can submit one more job: '; + + start_table(); + row1( "Commands" ); + row2( $line, 'Submit a job' ); + row2( "", 'Your account' ); + row2( "", 'Your computers' ); + row2( "", 'Log out' ); + end_table(); +} +else + exit_with_text( "You cannot submit any more jobs, you have reached your limit, clean up first !" ); + +page_tail(); +?>