2
// This file is part of BOINC.
3
// http://boinc.berkeley.edu
4
// Copyright (C) 2008 University of California
6
// BOINC is free software; you can redistribute it and/or modify it
7
// under the terms of the GNU Lesser General Public License
8
// as published by the Free Software Foundation,
9
// either version 3 of the License, or (at your option) any later version.
11
// BOINC is distributed in the hope that it will be useful,
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14
// See the GNU Lesser General Public License for more details.
16
// You should have received a copy of the GNU Lesser General Public License
17
// along with BOINC. If not, see <http://www.gnu.org/licenses/>.
20
// (or server_status.php?xml=1)
22
// outputs general information about BOINC server status gathered from
23
// config.xml or mysql database queries. If you are running all your
24
// services on one machine, and the database isn't so large, this should
25
// work right out of the box. Otherwise see configureables below.
27
// Daemons in config.xml are checked to see if they are running by ssh'ing
28
// into the respective hosts and searching for active pids. Passwordless
29
// logins must be in effect if there are multiple hosts involved.
31
// The database queries may be very slow. You might consider running these
32
// queries elsewhere via cronjob, outputing numbers into a readable file,
33
// and then getting the latest values with a `/bin/tail -1 data_file`.
34
// See commented example in the code.
36
// You can get an xml version of the stats via the web when the url has the
37
// optional "?xml=1" tag at the end, i.e
38
// http://yourboincproject.edu/server_status.php?xml=1
40
// You should edit the following variables in config.xml to suit your needs:
42
// <www_host> hostname of web server (default: same as <host>)
43
// <sched_host> hostname of scheduling server (default: same as <host>)
44
// <uldl_host> hostname of upload/download server (default: same as <host>)
45
// <uldl_pid> pid file of upload/download server httpd.conf
46
// (default: /etc/httpd/run/httpd.pid)
47
// <ssh_exe> path to ssh (default: /usr/bin/ssh)
48
// <ps_exe> path to ps (which supports "w" flag) (default: /bin/ps)
50
///////////////////////////////////////////////////////////////////////////////
52
require_once("../inc/util.inc");
53
require_once("../inc/xml.inc");
54
require_once("../inc/cache.inc");
55
require_once("../inc/translation.inc");
57
$xml = get_int("xml", true);
59
$cache_args = $languages_in_use[0];
60
if ($xml) $cache_args = "xml=1";
62
start_cache($cache_period, $cache_args);
64
// daemon status outputs: 1 (running) 0 (not running) or -1 (disabled)
66
function daemon_status($host, $pidname, $progname, $disabled) {
67
global $ssh_exe, $ps_exe, $project_host;
68
$path = "../../pid_$host/$pidname.pid";
71
$pid = file_get_contents($path);
74
$command = "$ps_exe ww $pid";
75
if ($host != $project_host) {
76
$command = "$ssh_exe $host " . $command;
78
$foo = exec($command);
80
if (strstr($foo, (string)$pid)) $running = 1;
84
if ($disabled == 1) $running = -1;
88
function show_status($host, $function, $running) {
90
$xmlstring = " <daemon>\n <host>$host</host>\n <command>$function</command>\n";
91
$htmlstring = "<tr><td>$function</td><td>$host</td>";
93
$xmlstring .= " <status>running</status>\n";
94
$htmlstring .= "<td class=\"running\">".tra("Running")."</td>\n";
95
} elseif ($running == 0) {
96
$xmlstring .= " <status>not running</status>\n";
97
$htmlstring .= "<td class=\"notrunning\">".tra("Not Running")."</td>\n";
99
$xmlstring .= " <status>disabled</status>\n";
100
$htmlstring .= "<td class=\"disabled\">".tra("Disabled")."</td>\n";
102
$xmlstring .= " </daemon>\n";
103
$htmlstring .= "</tr>\n";
112
function show_daemon_status($host, $pidname, $progname, $disabled) {
113
$running = daemon_status($host, $pidname, $progname, $disabled);
114
show_status($host, $pidname, $running);
117
function show_counts($key, $xmlkey, $value) {
119
$formattedvalue = number_format($value);
120
$xmlstring = " <$xmlkey>$value</$xmlkey>\n";
124
echo "<tr><td>$key</td><td>$formattedvalue</td></tr>";
129
function get_mysql_count ($query) {
130
$result = mysql_query("select count(*) as count from " . $query);
131
$count = mysql_fetch_object($result);
132
mysql_free_result($result);
133
return $count->count;
136
function get_mysql_value ($query) {
137
$result = mysql_query($query);
138
$row = mysql_fetch_object($result);
139
mysql_free_result($result);
143
function get_mysql_assoc($query) {
144
$sql = "SELECT * FROM app WHERE deprecated != 1";
145
$result = mysql_query($sql);
146
while($row = mysql_fetch_assoc($result)) {
149
mysql_free_result($result);
153
function get_mysql_user ($clause) {
154
$result = mysql_query("select count(userid) as userid from (SELECT distinct userid FROM result where validate_state=1 and received_time > (unix_timestamp()-(3600*24*1)) " . $clause . ") t");
155
$count = mysql_fetch_object($result);
156
mysql_free_result($result);
157
return $count->userid;
160
function get_cpu_time ($appid) {
161
$result = mysql_query("
162
Select ceil(avg(cpu_time)/3600*100)/100 as cpu_time,
163
ceil(min(cpu_time)/3600*100)/100 as min,
164
ceil(max(cpu_time)/3600*100)/100 as max
165
from (SELECT cpu_time FROM `result` WHERE appid = $appid and validate_state =1 and received_time > (unix_timestamp()-(3600*24)) ORDER BY `received_time` DESC limit 100) t");
166
$count = mysql_fetch_object($result);
167
mysql_free_result($result);
171
$config_xml = get_config();
172
$config_vars = parse_element($config_xml,"<config>");
173
$project_host = parse_element($config_vars,"<host>");
174
$www_host = parse_element($config_vars,"<www_host>");
175
if ($www_host == "") {
176
$www_host = $project_host;
178
$sched_host = parse_element($config_vars,"<sched_host>");
179
if ($sched_host == "") {
180
$sched_host = $project_host;
182
$uldl_pid = parse_element($config_vars,"<uldl_pid>");
183
if ($uldl_pid == "") {
184
$uldl_pid = "/etc/httpd/run/httpd.pid";
186
$uldl_host = parse_element($config_vars,"<uldl_host>");
187
if ($uldl_host == "") {
188
$uldl_host = $project_host;
190
$ssh_exe = parse_element($config_vars,"<ssh_exe>");
191
if ($ssh_exe == "") {
192
$ssh_exe = "/usr/bin/ssh";
194
$ps_exe = parse_element($config_vars,"<ps_exe>");
200
if (file_exists("../../local.revision")) {
201
$version = trim(file_get_contents("../../local.revision"));
205
$xmlstring = "<server_status>
206
<update_time>$now</update_time>
209
$xmlstring .= "<software_version>$version</software_version>\n";
211
$xmlstring .= " <daemon_status>\n";
216
page_head(tra("Project status"));
218
echo tra("Server software version: %1", $version) . " / ";
220
echo time_str(time()), "
223
<td width=40% valign=top>
224
<h2>".tra("Server status")."</h2>
225
<table border=0 cellpadding=4>
226
<tr><th>".tra("Program")."</th><th>".tra("Host")."</th><th>".tra("Status")."</th></tr>
230
// Are the data-driven web sites running? Check for existence of stop_web.
231
// If it is there, set $web_running to -1 for "disabled",
232
// otherwise it will be already set to 1 for "enabled."
233
// Set $www_host to the name of server hosting WWW site.
235
$web_running = !file_exists("../../stop_web");
236
if ($web_running == 0) $web_running = -1;
237
show_status($www_host, tra("data-driven web pages"), $web_running);
239
// Check for httpd.pid file of upload/download server.
241
$uldl_running = file_exists($uldl_pid);
242
if ($uldl_running == 0) $uldl_running = -1;
243
show_status($uldl_host, tra("upload/download server"), $uldl_running);
245
$sched_running = !file_exists("../../stop_sched");
246
show_status($sched_host, tra("scheduler"), $sched_running);
248
// parse through config.xml to get all daemons running
251
while ($thisxml = trim(parse_next_element($config_xml,"<daemon>",$cursor))) {
252
$host = parse_element($thisxml,"<host>");
254
$host = $project_host;
256
$cmd = parse_element($thisxml,"<cmd>");
257
list($ncmd) = explode(" ",$cmd);
258
$log = parse_element($thisxml,"<output>");
260
$log = $ncmd . ".log";
262
list($nlog) = explode(".log",$log);
263
$pid = parse_element($thisxml,"<pid_file>");
265
$pid = $ncmd . ".pid";
267
$disabled = parse_element($thisxml,"<disabled>");
268
show_daemon_status($host, $nlog, $ncmd, $disabled);
271
$xmlstring = " </daemon_status>\n <database_file_states>\n";
276
<tr><td align=right><b>".tra("Running:")."</b></td>
277
<td colspan=2>".tra("Program is operating normally")."</td></tr>
278
<tr><td align=right><b>".tra("Not Running:")."</b></td>
279
<td colspan=2>".tra("Program failed or the project is down")."</td></tr>
280
<tr><td align=right><b>".tra("Disabled:")."</b></td>
281
<td colspan=2>".tra("Program is disabled")."</td></tr>
285
<h2>".tra("Computing status")."</h2>
289
$retval = db_init_aux();
291
echo tra("The database server is not accessible");
294
echo "<table border=0 cellpadding=0 cellspacing=0><tr><td>
295
<table border=0 cellpadding=4>
296
<tr><th>".tra("Work")."</th><th>#</th></tr>
300
// If you are reading these values from a file rather than
301
// making live queries to the database, do something like this:
303
// $sendfile = "/home/boincadm/server_status_data/count_results_unsent.out";
304
// $n = `/bin/tail -1 $sendfile`;
305
// show_counts("Tasks ready to send","results_ready_to_send",$n);
308
tra("Tasks ready to send"),
309
"results_ready_to_send",
310
get_mysql_count("result where server_state = 2")
313
tra("Tasks in progress"),
314
"results_in_progress",
315
get_mysql_count("result where server_state = 4")
318
tra("Workunits waiting for validation"),
319
"workunits_waiting_for_validation",
320
get_mysql_count("workunit where need_validate=1")
323
tra("Workunits waiting for assimilation"),
324
"workunits_waiting_for_assimilation",
325
get_mysql_count("workunit where assimilate_state=1")
328
tra("Workunits waiting for file deletion"),
329
"workunits_waiting_for_deletion",
330
get_mysql_count("workunit where file_delete_state=1")
333
tra("Tasks waiting for file deletion"),
334
"results_waiting_for_deletion",
335
get_mysql_count("result where file_delete_state=1")
338
$result = mysql_query("select MIN(transition_time) as min from workunit");
339
$min = mysql_fetch_object($result);
340
mysql_free_result($result);
341
$gap = (time() - $min->min)/3600;
342
if (($gap < 0) || ($min->min == 0)) {
346
tra("Transitioner backlog (hours)"),
347
"transitioner_backlog_hours",
351
echo "</table></td><td>";
353
echo "<tr><th>".tra("Users")."</th><th>#</th></tr>";
355
tra("with recent credit"),
356
"users_with_recent_credit",
357
get_mysql_count("user where expavg_credit>1")
362
get_mysql_count("user where total_credit>0")
365
tra("registered in past 24 hours"),
366
"users_registered_in_past_24_hours",
367
get_mysql_count("user where create_time > (unix_timestamp() - (24*3600))")
369
echo "<tr><th>".tra("Computers")."</th><th>#</th></tr>";
371
tra("with recent credit"),
372
"hosts_with_recent_credit",
373
get_mysql_count("host where expavg_credit>1")
378
get_mysql_count("host where total_credit>0")
381
tra("registered in past 24 hours"),
382
"hosts_registered_in_past_24_hours",
383
get_mysql_count("host where create_time > (unix_timestamp() - (24*3600))")
385
// 100,000 cobblestones = 1 TeraFLOPS
386
// divide by 2, because double credits
388
tra("current GigaFLOPs"),
389
"current_floating_point_speed",
390
get_mysql_value("SELECT sum(expavg_credit)/200 as value FROM user")
394
echo "</td></tr></table>";
397
echo "<tr><th colspan=5>".tra("Tasks by application")."</th></tr>";
398
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")));
399
$apps = get_mysql_assoc("SELECT * FROM app WHERE deprecated != 1");
400
foreach($apps as $app) {
402
$uf_name = $app["user_friendly_name"];
403
echo "<tr><td>$uf_name</td>
404
<td>" . number_format(get_mysql_count("result where server_state = 2 and appid = $appid")) . "</td>
405
<td>" . number_format(get_mysql_count("result where server_state = 4 and appid = $appid")) . "</td>
407
$count = get_cpu_time($appid);
408
echo number_format($count->cpu_time,2) . " (" . number_format($count->min,2) . " - " . number_format($count->max,2) . ")";
410
<td>" . number_format(get_mysql_user("and appid = $appid")) . "</td>
418
$xmlstring = " </database_file_states>\n</server_status>\n";
430
end_cache($cache_period, $cache_args);