Passed
Push — master ( 197ef2...8f787b )
by Kevin
15:18 queued 11s
created

show_status_html()   F

Complexity

Conditions 12
Paths 768

Size

Total Lines 96
Code Lines 79

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 12
eloc 79
c 1
b 0
f 0
nc 768
nop 1
dl 0
loc 96
rs 2.9559

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
// This file is part of BOINC.
3
// http://boinc.berkeley.edu
4
// Copyright (C) 2014 University of California
5
//
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.
10
//
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.
15
//
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/>.
18
19
// Show server status page.
20
// Sources of data:
21
// - daemons on this host: use "ps" to see if each is running
22
//   (this could be made more efficient using a single "ps",
23
//   or it could be cached)
24
// - daemons on other hosts: get from a cached file generated periodically
25
//   by ops/remote_server_status.php
26
//   (we can't do this ourselves because apache can't generally ssh)
27
// - apps and job counts: get from a cached file that we generate ourselves
28
29
require_once("../inc/cache.inc");
30
require_once("../inc/util.inc");
31
require_once("../inc/xml.inc");
32
require_once("../inc/boinc_db.inc");
33
if(file_exists('../../release.inc'))
34
    include '../../release.inc';
35
36
if (!defined('STATUS_PAGE_TTL')) {
37
    define('STATUS_PAGE_TTL', 3600);
38
}
39
40
// trim a daemon command for display.
41
// For now, remove the cmdline args, but show the app if any
42
//
43
function command_display($cmd) {
44
    $x = explode(" -", $cmd);
45
    $prog = $x[0];
46
    $x = strpos($cmd, "-app ");
47
    if ($x) {
48
        $y = substr($cmd, $x);
49
        $y = explode(" ", $y);
50
        $app = $y[1];
51
        $prog .= " ($app)";
52
    }
53
    return $prog;
54
}
55
56
function daemon_html($d) {
57
    switch ($d->status) {
58
    case 0:
59
        $s = tra("Not Running");
60
        $c = "bg-danger";
61
        break;
62
    case 1:
63
        $s = tra("Running");
64
        $c = "bg-success";
65
        break;
66
    default:
0 ignored issues
show
Coding Style introduced by
DEFAULT keyword must be indented 4 spaces from SWITCH keyword
Loading history...
67
        $s = tra("Disabled");
68
        $c = "bg-warning";
69
        break;
70
    }
71
    echo "<tr>
72
        <td>".command_display($d->cmd)."</td>
73
        <td>$d->host</td>
74
        <td class=\"$c\"><nobr>$s</nobr></td>
75
        </tr>
76
    ";
77
}
78
79
function daemon_xml($d) {
80
    switch ($d->status) {
81
    case 0: $s = "not running"; break;
82
    case 1: $s = "running"; break;
83
    default: $s = "disabled";
0 ignored issues
show
Coding Style introduced by
DEFAULT keyword must be indented 4 spaces from SWITCH keyword
Loading history...
Coding Style introduced by
DEFAULT case must have a breaking statement
Loading history...
84
    }
85
    echo "  <daemon>
86
        <host>$d->host</host>
87
        <command>".command_display($d->cmd)."</command>
88
        <status>$s</status>
89
    </daemon>
90
";
91
}
92
93
function item_xml($name, $val) {
94
    if (!$val) $val = 0;
95
    echo "   <$name>$val</$name>\n";
96
}
97
98
function item_html($name, $val) {
99
    $name = tra($name);
100
    echo "<tr><td>$name</td><td>$val</td></tr>\n";
101
    //echo "<tr><td align=right>$name</td><td align=right>$val</td></tr>\n";
102
}
103
104
function show_status_html($x) {
105
    page_head(tra("Project status"));
106
    $j = $x->jobs;
107
    $daemons = $x->daemons;
108
    start_table();
109
    echo "<tr><td>\n";
110
            echo "
111
                 <h3>".tra("Server status")."</h3>
112
            ";
113
            start_table('table-striped');
114
            table_header(tra("Program"), tra("Host"), tra("Status"));
115
            foreach ($daemons->local_daemons as $d) {
116
                daemon_html($d);
117
            }
118
            foreach ($daemons->remote_daemons as $d) {
119
                daemon_html($d);
120
            }
121
            foreach ($daemons->disabled_daemons as $d) {
122
                daemon_html($d);
123
            }
124
            end_table();
125
126
            if ($daemons->cached_time) {
127
                echo "<br>Remote daemon status as of ", time_str($daemons->cached_time);
128
            }
129
            if ($daemons->missing_remote_status) {
130
                echo "<br>Status of remote daemons is missing\n";
131
            }
132
            if (function_exists('server_status_project_info')) {
133
                echo "<br>";
134
                server_status_project_info();
135
            }
136
    echo "</td><td>\n";
137
            echo "<h3>".tra("Computing status")."</h3>\n";
138
            echo "<h4>".tra("Work")."</h4>\n";
139
            start_table('table-striped');
140
            item_html("Tasks ready to send", $j->results_ready_to_send);
141
            item_html("Tasks in progress", $j->results_in_progress);
142
            item_html("Workunits waiting for validation", $j->wus_need_validate);
143
            item_html("Workunits waiting for assimilation", $j->wus_need_assimilate);
144
            item_html("Workunits waiting for file deletion", $j->wus_need_file_delete);
145
            item_html("Tasks waiting for file deletion", $j->results_need_file_delete);
146
            item_html("Transitioner backlog (hours)", number_format($j->transitioner_backlog, 2));
147
            end_table();
148
            echo "<h4>".tra("Users")."</h4>\n";
149
            start_table('table-striped');
150
            item_html("With credit", $j->users_with_credit);
151
            item_html("With recent credit", $j->users_with_recent_credit);
152
            item_html("Registered in past 24 hours", $j->users_past_24_hours);
153
            end_table();
154
            echo "<h4>".tra("Computers")."</h4>\n";
155
            start_table('table-striped');
156
            item_html("With credit", $j->hosts_with_credit);
157
            item_html("With recent credit", $j->hosts_with_recent_credit);
158
            item_html("Registered in past 24 hours", $j->hosts_past_24_hours);
159
            item_html("Current GigaFLOPS", round($j->flops, 2));
160
            end_table();
161
    echo "</td></tr>\n";
162
    end_table();
163
    echo "<h3>".tra("Tasks by application")."</h3>\n";
164
    start_table('table-striped');
165
    table_header(
166
        tra("Application"),
167
        tra("Unsent"),
168
        tra("In progress"),
169
        tra("Runtime of last 100 tasks in hours: average, min, max"),
170
        tra("Users in last 24 hours")
171
    );
172
    foreach ($j->apps as $app) {
173
        $avg = round($app->info->avg, 2);
174
        $min = round($app->info->min, 2);
175
        $max = round($app->info->max, 2);
176
        $x = $max?"$avg ($min - $max)":"---";
177
        $u = $app->info->users;
178
        echo "<tr>
179
            <td>$app->user_friendly_name</td>
180
            <td>$app->unsent</td>
181
            <td>$app->in_progress</td>
182
            <td>$x</td>
183
            <td>$u</td>
184
            </tr>
185
        ";
186
    }
187
    end_table();
188
    
189
    global $server_version;
190
    global $git_commit;
191
    if ( isset($server_version) && isset($git_commit) ) {
192
        echo "Server version: $server_version (<a href=https://github.com/BOINC/boinc/commit/$git_commit>$git_commit)</a>)<br>";
193
    }
194
195
    if ($j->db_revision) {
196
        echo tra("Database schema version: "), $j->db_revision;
197
    }
198
    echo "<p>Task data as of ".time_str($j->cached_time);
199
    page_tail();
200
}
201
202
function show_status_xml($x) {
203
    xml_header();
204
    echo "<server_status>\n<daemon_status>\n";
205
206
    $daemons = $x->daemons;
207
    foreach ($daemons->local_daemons as $d) {
208
        daemon_xml($d);
209
    }
210
    foreach ($daemons->remote_daemons as $d) {
211
        daemon_xml($d);
212
    }
213
    foreach ($daemons->disabled_daemons as $d) {
214
        daemon_xml($d);
215
    }
216
    echo "</daemon_status>\n<database_file_states>\n";
217
    $j = $x->jobs;
218
    item_xml("results_ready_to_send", $j->results_ready_to_send);
219
    item_xml("results_in_progress", $j->results_in_progress);
220
    item_xml("workunits_waiting_for_validation", $j->wus_need_validate);
221
    item_xml("workunits_waiting_for_assimilation", $j->wus_need_assimilate);
222
    item_xml("workunits_waiting_for_deletion", $j->wus_need_file_delete);
223
    item_xml("results_waiting_for_deletion", $j->results_need_file_delete);
224
    item_xml("transitioner_backlog_hours", $j->transitioner_backlog);
225
    item_xml("users_with_recent_credit", $j->users_with_recent_credit);
226
    item_xml("users_with_credit", $j->users_with_credit);
227
    item_xml("users_registered_in_past_24_hours", $j->users_past_24_hours);
228
    item_xml("hosts_with_recent_credit", $j->hosts_with_recent_credit);
229
    item_xml("hosts_with_credit", $j->hosts_with_credit);
230
    item_xml("hosts_registered_in_past_24_hours", $j->hosts_past_24_hours);
231
    item_xml("current_floating_point_speed", $j->flops);
232
    echo "<tasks_by_app>\n";
233
    foreach ($j->apps as $app) {
234
        echo "<app>\n";
235
        item_xml("id", $app->id);
236
        item_xml("name", $app->name);
237
        item_xml("unsent", $app->unsent);
238
        item_xml("in_progress", $app->in_progress);
239
        item_xml("avg_runtime", $app->info->avg);
240
        item_xml("min_runtime", $app->info->min);
241
        item_xml("max_runtime", $app->info->max);
242
        item_xml("users", $app->info->users);
243
        echo "</app>\n";
244
    }
245
    echo "</tasks_by_app>
246
</database_file_states>
247
</server_status>
248
";
249
}
250
251
function local_daemon_running($cmd, $pidname, $host) {
252
    if (!$pidname) {
253
        $cmd = trim($cmd);
254
        $x = explode(" ", $cmd);
255
        $prog = $x[0];
256
        $pidname = $prog . '.pid';
257
    }
258
    $path = "../../pid_$host/$pidname";
259
    if (is_file($path)) {
260
        $pid = file_get_contents($path);
261
        if ($pid) {
262
            $pid = trim($pid);
263
            $out = Array();
0 ignored issues
show
Coding Style introduced by
Array keyword should be lower case; expected "array" but found "Array"
Loading history...
Coding Style introduced by
As per coding-style, PHP keywords should be in lowercase; expected array, but found Array.
Loading history...
264
            exec("ps -ww $pid", $out);
265
            foreach ($out as $y) {
266
                if (strstr($y, (string)$pid)) return 1;
267
            }
268
        }
269
    }
270
    return 0;
271
}
272
273
// returns a data structure of the form
274
// local_daemons: array of
275
//   cmd, status
276
// remote_daemons: array of
277
//   cmd, host, status
278
// disabled_daemons: array of
279
//   cmd, host
280
//
281
function get_daemon_status() {
282
    $c = simplexml_load_file("../../config.xml");
283
    if (!$c) {
0 ignored issues
show
introduced by
$c is of type SimpleXMLElement, thus it always evaluated to true.
Loading history...
284
        die("can't parse config file\n");
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
285
    }
286
    $daemons = $c->daemons;
287
    $config = $c->config;
288
    $main_host = trim((string)$config->host);
289
    $master_url = trim((string)$config->master_url);
290
    $u = parse_url($master_url);
291
    if (!array_key_exists("host", $u)) {
292
        print_r($u);
293
        die("can't parse URL $master_url");
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
294
    }
295
    $master_host = $u["host"];
296
    if ($config->www_host) {
297
        $web_host = trim((string) $config->www_host);
298
    } else {
299
        $web_host = $main_host;
300
    }
301
    if ($config->sched_host) {
302
        $sched_host = trim((string) $config->sched_host);
303
    } else {
304
        $sched_host = $main_host;
305
    }
306
    $have_remote = false;
307
    $local_daemons = array();
308
    $disabled_daemons = array();
309
310
    // the upload and download servers are sort of daemons too
311
    //
312
    $url = trim((string) $config->download_url);
313
    $u = parse_url($url);
314
    $h = $u["host"];
315
    if ($h == $master_host) {
316
        $y = new StdClass;
317
        $y->cmd = "Download server";
318
        $y->host = $h;
319
        $y->status = 1;
320
        $local_daemons[] = $y;
321
    } else {
322
        $have_remote = true;
323
    }
324
    $url = trim((string) $config->upload_url);
325
    $u = parse_url($url);
326
    $h = $u["host"];
327
    if ($h == $master_host) {
328
        $y = new StdClass;
329
        $y->cmd = "Upload server";
330
        $y->host = $h;
331
        $y->status = !file_exists("../../stop_upload");;
332
        $local_daemons[] = $y;
333
    } else {
334
        $have_remote = true;
335
    }
336
337
    // Scheduler is a daemon too
338
    //
339
    if ($sched_host == $main_host) {
340
        $y = new StdClass;
341
        $y->cmd = "Scheduler";
342
        $y->host = $sched_host;
343
        $y->status = !file_exists("../../stop_sched");;
344
        $local_daemons[] = $y;
345
    } else {
346
        $have_remote = true;
347
    }
348
349
    foreach ($daemons->daemon as $d) {
350
        if ((int)$d->disabled != 0) {
351
            $x = new StdClass;
352
            $x->cmd = (string)$d->cmd;
353
            $x->host = (string)$d->host;
354
            if (!$x->host) $x->host = $main_host;
355
            $x->status = -1;
356
            $disabled_daemons[] = $x;
357
            continue;
358
        }
359
        $host = $d->host?(string)$d->host:$main_host;
360
        if ($host != $web_host) {
361
            $have_remote = true;
362
            continue;
363
        }
364
        $x = new StdClass;
365
        $x->cmd = (string)$d->cmd;
366
        $x->status = local_daemon_running($x->cmd, trim($d->pid_file), $web_host);
367
        $x->host = $web_host;
368
        $local_daemons[] = $x;
369
370
    }
371
372
    $x = new StdClass;
373
    $x->local_daemons = $local_daemons;
374
    $x->disabled_daemons = $disabled_daemons;
375
    $x->missing_remote_status = false;
376
    $x->cached_time = 0;
377
    $x->remote_daemons = array();
378
    if ($have_remote) {
379
        $f = @file_get_contents("../cache/remote_server_status");
380
        if ($f) {
381
            $x->remote_daemons = unserialize($f);
382
            $x->cached_time = filemtime("../cache/remote_server_status");
383
        } else {
384
            $x->missing_remote_status = true;
385
        }
386
    }
387
    return $x;
388
}
389
390
function get_job_status() {
391
    $s = unserialize(get_cached_data(STATUS_PAGE_TTL, "job_status"));
0 ignored issues
show
Bug introduced by
It seems like get_cached_data(STATUS_PAGE_TTL, 'job_status') can also be of type false; however, parameter $str of unserialize() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

391
    $s = unserialize(/** @scrutinizer ignore-type */ get_cached_data(STATUS_PAGE_TTL, "job_status"));
Loading history...
392
    if ($s) {
393
        return $s;
394
    }
395
396
    $s = new StdClass;
397
    $apps = BoincApp::enum("deprecated=0");
398
    foreach ($apps as $app) {
399
        $info = BoincDB::get()->lookup_fields("result", "stdClass",
400
            "ceil(avg(elapsed_time)/3600*100)/100 as avg,
401
            ceil(min(elapsed_time)/3600*100)/100 as min,
402
            ceil(max(elapsed_time)/3600*100)/100 as max,
403
            count(distinct userid) as users",
404
            "appid = $app->id
405
            AND validate_state=1
406
            AND received_time > (unix_timestamp()-86400)
407
            "
408
        );
409
        $app->info = $info;
410
        $app->unsent = BoincResult::count("appid=$app->id and server_state=2");
411
        $app->in_progress = BoincResult::count("appid=$app->id and server_state=4");
412
    }
413
    $s->apps = $apps;
414
    $s->results_ready_to_send = BoincResult::count("server_state=2");
415
    $s->results_in_progress = BoincResult::count("server_state=4");
416
    $s->results_need_file_delete = BoincResult::count("file_delete_state=1");
417
    $s->wus_need_validate = BoincWorkunit::count("need_validate=1");
418
    $s->wus_need_assimilate = BoincWorkunit::count("assimilate_state=1");
419
    $s->wus_need_file_delete = BoincWorkunit::count("file_delete_state=1");
420
    $x = BoincDB::get()->lookup_fields("workunit", "stdClass", "MIN(transition_time) as min", "TRUE");
421
    $gap = (time() - $x->min)/3600;
422
    if (($gap < 0) || ($x->min == 0)) {
423
        $gap = 0;
424
    }
425
    $s->transitioner_backlog = $gap;
426
    $s->users_with_recent_credit = BoincUser::count("expavg_credit>1");
427
    $s->users_with_credit = BoincUser::count("total_credit>1");
428
    $s->users_past_24_hours = BoincUser::count("create_time > (unix_timestamp() - 86400)");
429
    $s->hosts_with_recent_credit = BoincHost::count("expavg_credit>1");
430
    $s->hosts_with_credit = BoincHost::count("total_credit>1");
431
    $s->hosts_past_24_hours = BoincHost::count("create_time > (unix_timestamp() - 86400)");
432
    $s->flops = BoincUser::sum("expavg_credit")/200;
433
434
    $s->db_revision = null;
435
    if (file_exists("../../db_revision")) {
436
        $s->db_revision = trim(file_get_contents("../../db_revision"));
437
    }
438
439
    $s->cached_time = time();
440
    $e = set_cached_data(STATUS_PAGE_TTL, serialize($s), "job_status");
441
    if ($e) echo "set_cached_data(): $e\n";
442
    return $s;
443
}
444
445
function main() {
446
    $x = new StdClass;
447
    $x->daemons = get_daemon_status();
448
    $x->jobs = get_job_status();
449
    if (get_int('xml', true)) {
450
        show_status_xml($x);
451
    } else {
452
        show_status_html($x);
453
    }
454
}
455
456
main();
457
?>
458