. // server_status.php // (or server_status.php?xml=1) // // outputs general information about BOINC server status gathered from // config.xml or mysql database queries. If you are running all your // services on one machine, and the database isn't so large, this should // work right out of the box. Otherwise see configureables below. // // Daemons in config.xml are checked to see if they are running by ssh'ing // into the respective hosts and searching for active pids. Passwordless // logins must be in effect if there are multiple hosts involved. // // The database queries may be very slow. You might consider running these // queries elsewhere via cronjob, outputing numbers into a readable file, // and then getting the latest values with a `/bin/tail -1 data_file`. // See commented example in the code. // // You can get an xml version of the stats via the web when the url has the // optional "?xml=1" tag at the end, i.e // http://yourboincproject.edu/server_status.php?xml=1 // // You should edit the following variables in config.xml to suit your needs: // // hostname of web server (default: same as ) // hostname of scheduling server (default: same as ) // hostname of upload/download server (default: same as ) // pid file of upload/download server httpd.conf // (default: /etc/httpd/run/httpd.pid) // path to ssh (default: /usr/bin/ssh) // path to ps (which supports "w" flag) (default: /bin/ps) /////////////////////////////////////////////////////////////////////////////// require_once("../inc/util.inc"); require_once("../inc/xml.inc"); require_once("../inc/cache.inc"); require_once("../inc/translation.inc"); check_get_args(array("xml")); $xml = get_int("xml", true); // daemon status outputs: 1 (running) 0 (not running) or -1 (disabled) // function daemon_status($host, $pidname, $progname, $disabled) { global $ssh_exe, $ps_exe, $project_host, $project_dir; if ($disabled == 1) return -1; $path = "$project_dir/pid_$host/$pidname"; if ($host != $project_host) { $command = "$ssh_exe $host $project_dir/bin/pshelper $path"; $foo = exec($command); $running = 1; if ($foo) { if (strstr($foo, "false")) $running = 0; } else $running = 0; return $running; } $running = 0; if (is_file($path)) { $pid = file_get_contents($path); if ($pid) { $pid = trim($pid); $command = "$ps_exe ww $pid"; $foo = exec($command); if ($foo) { if (strstr($foo, (string)$pid)) $running = 1; } } } return $running; } function show_status($host, $progname, $running) { global $xml; $xmlstring = " \n $host\n $progname\n"; $htmlstring = "$progname$host"; if ($running == 1) { $xmlstring .= " running\n"; $htmlstring .= "".tra("Running")."\n"; } elseif ($running == 0) { $xmlstring .= " not running\n"; $htmlstring .= "".tra("Not Running")."\n"; } else { $xmlstring .= " disabled\n"; $htmlstring .= "".tra("Disabled")."\n"; } $xmlstring .= " \n"; $htmlstring .= "\n"; if ($xml) { echo $xmlstring; } else { echo $htmlstring; } return 0; } function show_daemon_status($host, $pidname, $progname, $disabled) { $running = daemon_status($host, $pidname, $progname, $disabled); show_status($host, $progname, $running); } function show_counts($key, $xmlkey, $value) { global $xml; $formattedvalue = number_format($value); $xmlstring = " <$xmlkey>$value\n"; if ($xml) { echo $xmlstring; } else { echo "$key$formattedvalue"; } return 0; } function get_mysql_count($table, $query) { $count = unserialize(get_cached_data(3600, "get_mysql_count".$table.$query)); if ($count == false) { $count = BoincDB::get()->count($table,$query); set_cached_data(3600, serialize($count), "get_mysql_count".$table.$query); } return $count; } function get_mysql_sum($table, $field) { $value = unserialize(get_cached_data(3600, "get_mysql_sum".$table.$field)); if ($value == false) { $value = BoincDB::get()->sum($table, $field); set_cached_data(3600, serialize($value), "get_mysql_sum".$table.$field); } return $value; } function get_cached_apps() { $apps = unserialize(get_cached_data(3600, "get_cached_apps")); if ($apps == false) { $apps = BoincApp::enum("deprecated=0"); set_cached_data(3600, serialize($apps), "get_cached_apps"); } return $apps; } function get_runtime_info($appid) { $info = unserialize(get_cached_data(3600, "get_runtime_info".$appid)); if ($info == false) { $info = BoincDB::get()->lookup_fields("result", "stdClass", "ceil(avg(elapsed_time)/3600*100)/100 as avg, ceil(min(elapsed_time)/3600*100)/100 as min, ceil(max(elapsed_time)/3600*100)/100 as max, count(distinct userid) as users", "appid = $appid AND validate_state=1 AND received_time > (unix_timestamp()-(3600*24)) " ); if (!$info){ // No recent jobs sound $info = new stdClass; $info->avg = $info->min = $info->max = $info->users = 0; } set_cached_data(3600, serialize($info), "get_runtime_info".$appid); } return $info; } $config_xml = get_config(); $config_vars = parse_element($config_xml,""); $project_host = parse_element($config_vars,""); $www_host = parse_element($config_vars,""); if ($www_host == "") { $www_host = $project_host; } $sched_host = parse_element($config_vars,""); if ($sched_host == "") { $sched_host = $project_host; } $uldl_pid = parse_element($config_vars,""); if ($uldl_pid == "") { $uldl_pid = "/etc/httpd/run/httpd.pid"; } $uldl_host = parse_element($config_vars,""); if ($uldl_host == "") { $uldl_host = $project_host; } $project_dir = parse_element($config_vars,""); if ($project_dir == "") { $project_dir = "../.."; } $ssh_exe = parse_element($config_vars,""); if ($ssh_exe == "") { $ssh_exe = "/usr/bin/ssh"; } $ps_exe = parse_element($config_vars,""); if ($ps_exe == "") { $ps_exe = "/bin/ps"; } $version = null; if (file_exists("../../local.revision")) { $version = trim(file_get_contents("../../local.revision")); } $now = time(); $xmlstring = " $now "; if ($version) { $xmlstring .= "$version\n"; } $xmlstring .= " \n"; if ($xml) { xml_header(); echo $xmlstring; } else { page_head(tra("Project status")); if ($version) { echo tra("Server software version: %1", $version) . " / "; } echo time_str(time()), "

".tra("Server status")."

"; } ; // Are the data-driven web sites running? Check for existence of stop_web. // If it is there, set $web_running to -1 for "disabled", // otherwise it will be already set to 1 for "enabled." // Set $www_host to the name of server hosting WWW site. // $web_running = !file_exists("../../stop_web"); if ($web_running == 0) $web_running = -1; show_status($www_host, tra("data-driven web pages"), $web_running); // Check for httpd.pid file of upload/download server. // $uldl_running = file_exists($uldl_pid); if ($uldl_running == 0) $uldl_running = -1; show_status($uldl_host, tra("upload/download server"), $uldl_running); $sched_running = !file_exists("../../stop_sched"); show_status($sched_host, tra("scheduler"), $sched_running); // parse through config.xml to get all daemons running // $cursor = 0; while ($thisxml = trim(parse_next_element($config_xml,"",$cursor))) { $host = parse_element($thisxml,""); if ($host == "") { $host = $project_host; } $cmd = parse_element($thisxml,""); list($cmd) = explode(" ", $cmd); $log = parse_element($thisxml,""); if (!$log) { $log = $cmd . ".log"; } list($log) = explode(".log", $log); $pid = parse_element($thisxml,""); if (!$pid) { $pid = $cmd . ".pid"; } $disabled = parse_element($thisxml,""); // surrogate for command list($c) = explode(".", $log); show_daemon_status($host, $pid, $c, $disabled); } $xmlstring = " \n \n"; if ($xml) { echo $xmlstring; } else { echo "
".tra("Program")."".tra("Host")."".tra("Status")."
".tra("Running:")." ".tra("Program is operating normally")."
".tra("Not Running:")." ".tra("Program failed or the project is down")."
".tra("Disabled:")." ".tra("Program is disabled")."

".tra("Computing status")."

"; } $retval = db_init_aux(); if ($retval) { echo tra("The database server is not accessible"); } else { if (!$xml) { echo ""; row_heading_array( array( tra("application"), tra("unsent"), tra("in progress"), tra("avg runtime of last 100 results in h (min-max)"), tra("users in last 24h") ) ); } $apps = get_cached_apps(); if ($xml) { echo " \n"; } foreach($apps as $app) { $info = get_runtime_info($app->id); if ($xml) { echo " \n"; echo " ".$app->id."\n"; echo " ".$app->name."\n"; echo " ".get_mysql_count("result", "server_state = 2 and appid = ".$app->id)."\n"; echo " ".get_mysql_count("result", "server_state = 4 and appid = ".$app->id)."\n"; echo " ".round($info->avg, 2)."\n"; echo " ".round($info->min, 2)."\n"; echo " ".round($info->max, 2)."\n"; echo " ".$info->users."\n"; echo " \n"; } else { echo "" ; } } if ($xml) { echo " \n"; } else { end_table(); } } $xmlstring = " \n\n"; if ($xml) { echo $xmlstring; } else { echo "
"; } // If you are reading these values from a file rather than // making live queries to the database, do something like this: // // $sendfile = "/home/boincadm/server_status_data/count_results_unsent.out"; // $n = `/bin/tail -1 $sendfile`; // show_counts("Tasks ready to send","results_ready_to_send",$n); show_counts( tra("Tasks ready to send"), "results_ready_to_send", get_mysql_count("result", "server_state = 2") ); show_counts( tra("Tasks in progress"), "results_in_progress", get_mysql_count("result", "server_state = 4") ); show_counts( tra("Workunits waiting for validation"), "workunits_waiting_for_validation", get_mysql_count("workunit", "need_validate=1") ); show_counts( tra("Workunits waiting for assimilation"), "workunits_waiting_for_assimilation", get_mysql_count("workunit", "assimilate_state=1") ); show_counts( tra("Workunits waiting for file deletion"), "workunits_waiting_for_deletion", get_mysql_count("workunit", "file_delete_state=1") ); show_counts( tra("Tasks waiting for file deletion"), "results_waiting_for_deletion", get_mysql_count("result", "file_delete_state=1") ); $gap = unserialize(get_cached_data(3600, "transitioner_backlog")); if ($gap === false) { $min = BoincDB::get()->lookup_fields("workunit", "stdClass", "MIN(transition_time) as min", "TRUE"); //$gap = BoincDB::get()->min("workunit", "transition_time"); $gap = time()-$gap/3600; $gap = (time() - $min->min)/3600; if (($gap < 0) || ($min->min == 0)) { $gap = 0; } set_cached_data(3600, serialize($gap), "transitioner_backlog"); } show_counts( tra("Transitioner backlog (hours)"), "transitioner_backlog_hours", $gap ); if (!$xml) { echo "
".tra("Work")."#
"; echo ""; echo ""; } show_counts( tra("with recent credit"), "users_with_recent_credit", get_mysql_count("user", "expavg_credit>1") ); show_counts( tra("with credit"), "users_with_credit", get_mysql_count("user", "total_credit>0") ); show_counts( tra("registered in past 24 hours"), "users_registered_in_past_24_hours", get_mysql_count("user", "create_time > (unix_timestamp() - (24*3600))") ); if (!$xml) { echo ""; } show_counts( tra("with recent credit"), "hosts_with_recent_credit", get_mysql_count("host", "expavg_credit>1") ); show_counts( tra("with credit"), "hosts_with_credit", get_mysql_count("host", "total_credit>0") ); show_counts( tra("registered in past 24 hours"), "hosts_registered_in_past_24_hours", get_mysql_count("host", "create_time > (unix_timestamp() - (24*3600))") ); // 200 cobblestones = 1 GigaFLOPS show_counts( tra("current GigaFLOPs"), "current_floating_point_speed", get_mysql_sum("user", "expavg_credit/200") ); if (!$xml) { end_table(); echo "
".tra("Users")."#
".tra("Computers")."#
"; start_table(); echo "
".tra("Tasks by application")."
".$app->user_friendly_name." " . number_format(get_mysql_count("result", "server_state = 2 and appid = ".$app->id)) . " " . number_format(get_mysql_count("result", "server_state = 4 and appid = ".$app->id)) . " " ; echo number_format($info->avg,2) . " (" . number_format($info->min,2) . " - " . number_format($info->max,2) . ")"; echo " " . number_format($info->users) . "
"; page_tail(); } ?>