show_status_html()   F
last analyzed

Complexity

Conditions 12
Paths 1024

Size

Total Lines 112
Code Lines 89

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 12
eloc 89
c 1
b 1
f 0
nc 1024
nop 1
dl 0
loc 112
rs 2.48

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
// Get server status.
20
//
21
// default: show as web page
22
// ?xml=1:  show as XML
23
// ?counts=1: show only overall job counts, w/o caching
24
//      (for remote job submission systems)
25
// Sources of data:
26
// - daemons on this host: use "ps" to see if each is running
27
//   (this could be made more efficient using a single "ps",
28
//   or it could be cached)
29
// - daemons on other hosts: get from a cached file generated periodically
30
//   by ops/remote_server_status.php
31
//   (we can't do this ourselves because apache can't generally ssh)
32
// - apps and job counts: get from a cached file that we generate ourselves
33
34
require_once("../inc/cache.inc");
35
require_once("../inc/util.inc");
36
require_once("../inc/xml.inc");
37
require_once("../inc/boinc_db.inc");
38
require_once("../inc/server_version.inc");
39
40
if (!defined('STATUS_PAGE_TTL')) {
41
    define('STATUS_PAGE_TTL', 3600);
42
}
43
44
// trim a daemon command for display.
45
// For now, remove the cmdline args, but show the app if any
46
//
47
function command_display($cmd) {
48
    $x = explode(" -", $cmd);
49
    $prog = $x[0];
50
    $x = strpos($cmd, "-app ");
51
    if ($x) {
52
        $y = substr($cmd, $x);
53
        $y = explode(" ", $y);
54
        $app = $y[1];
55
        $prog .= " ($app)";
56
    }
57
    return $prog;
58
}
59
60
function daemon_html($d) {
61
    switch ($d->status) {
62
    case 0:
63
        $s = tra("Not Running");
64
        $c = "bg-danger";
65
        break;
66
    case 1:
67
        $s = tra("Running");
68
        $c = "bg-success";
69
        break;
70
    default:
0 ignored issues
show
Coding Style introduced by
DEFAULT keyword must be indented 4 spaces from SWITCH keyword
Loading history...
71
        $s = tra("Disabled");
72
        $c = "bg-warning";
73
        break;
74
    }
75
    echo "<tr>
76
        <td>".command_display($d->cmd)."</td>
77
        <td>$d->host</td>
78
        <td class=\"$c\"><nobr>$s</nobr></td>
79
        </tr>
80
    ";
81
}
82
83
function daemon_xml($d) {
84
    switch ($d->status) {
85
    case 0: $s = "not running"; break;
86
    case 1: $s = "running"; break;
87
    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...
88
    }
89
    echo "  <daemon>
90
        <host>$d->host</host>
91
        <command>".command_display($d->cmd)."</command>
92
        <status>$s</status>
93
    </daemon>
94
";
95
}
96
97
function item_xml($name, $val) {
98
    if (!$val) $val = 0;
99
    echo "   <$name>$val</$name>\n";
100
}
101
102
function item_html($name, $val) {
103
    $name = tra($name);
104
    echo "<tr><td>$name</td><td>$val</td></tr>\n";
105
    //echo "<tr><td align=right>$name</td><td align=right>$val</td></tr>\n";
106
}
107
108
function show_status_html($x) {
109
    global $server_version, $server_version_str;
110
111
    page_head(tra("Project status"));
112
    $j = $x->jobs;
113
    $daemons = $x->daemons;
114
    start_table();
115
    echo "<tr><td>\n";
116
    echo "
117
         <h3>".tra("Server status")."</h3>
118
    ";
119
    start_table('table-striped');
120
    table_header(tra("Program"), tra("Host"), tra("Status"));
121
    foreach ($daemons->local_daemons as $d) {
122
        daemon_html($d);
123
    }
124
    foreach ($daemons->remote_daemons as $d) {
125
        daemon_html($d);
126
    }
127
    foreach ($daemons->disabled_daemons as $d) {
128
        daemon_html($d);
129
    }
130
    end_table();
131
132
    if ($daemons->cached_time) {
133
        echo "<br>Remote daemon status as of ", time_str($daemons->cached_time);
134
    }
135
    if ($daemons->missing_remote_status) {
136
        echo "<br>Status of remote daemons is missing\n";
137
    }
138
    if (function_exists('server_status_project_info')) {
139
        echo "<br>";
140
        server_status_project_info();
141
    }
142
    echo "</td><td>\n";
143
    echo "<h3>".tra("Computing status")."</h3>\n";
144
    echo "<h4>".tra("Work")."</h4>\n";
145
    start_table('table-striped');
146
    item_html("Tasks ready to send", $j->results_ready_to_send);
147
    item_html("Tasks in progress", $j->results_in_progress);
148
    item_html("Workunits waiting for validation", $j->wus_need_validate);
149
    item_html("Workunits waiting for assimilation", $j->wus_need_assimilate);
150
    item_html("Workunits waiting for file deletion", $j->wus_need_file_delete);
151
    item_html("Tasks waiting for file deletion", $j->results_need_file_delete);
152
    item_html("Transitioner backlog (hours)", number_format($j->transitioner_backlog, 2));
153
    end_table();
154
    echo "<h4>".tra("Users")."</h4>\n";
155
    start_table('table-striped');
156
    item_html("With credit", $j->users_with_credit);
157
    item_html("With recent credit", $j->users_with_recent_credit);
158
    item_html("Registered in past 24 hours", $j->users_past_24_hours);
159
    end_table();
160
    echo "<h4>".tra("Computers")."</h4>\n";
161
    start_table('table-striped');
162
    item_html("With credit", $j->hosts_with_credit);
163
    item_html("With recent credit", $j->hosts_with_recent_credit);
164
    item_html("Registered in past 24 hours", $j->hosts_past_24_hours);
165
    item_html("Current GigaFLOPS", round($j->flops, 2));
166
    end_table();
167
    echo "</td></tr>\n";
168
    end_table();
169
    echo "<h3>".tra("Tasks by application")."</h3>\n";
170
    start_table('table-striped');
171
    table_header(
172
        tra("Application"),
173
        tra("Unsent"),
174
        tra("In progress"),
175
        tra("Runtime of recent tasks in hours: average, min, max"),
176
        tra("Users in last 24 hours")
177
    );
178
    foreach ($j->apps as $app) {
179
        if ($app->info) {
180
            $avg = round($app->info->avg, 2);
181
            $min = round($app->info->min, 2);
182
            $max = round($app->info->max, 2);
183
            $x = $max?"$avg ($min - $max)":"---";
184
            $u = $app->info->users;
185
        } else {
186
            $x = '---';
187
            $u = '---';
188
        }
189
        echo "<tr>
190
            <td>$app->user_friendly_name</td>
191
            <td>$app->unsent</td>
192
            <td>$app->in_progress</td>
193
            <td>$x</td>
194
            <td>$u</td>
195
            </tr>
196
        ";
197
    }
198
    end_table();
199
200
    // show server software version.
201
    // If it's a release (minor# is even) link to github branch
202
    //
203
    echo "Server software version: $server_version_str";
204
    if ($server_version[1]%2 == 0) {
205
        $url = sprintf("%s/%d/%d.%d",
206
            "https://github.com/BOINC/boinc/tree/server_release",
207
            $server_version[0],
208
            $server_version[0],
209
            $server_version[1]
210
        );
211
        echo " <a href=\"$url\">View source on Github</a>.";
212
    }
213
    echo "<br>\n";
214
215
    if ($j->db_revision) {
216
        echo tra("Database schema version: "), $j->db_revision;
217
    }
218
    echo "<p>Task data as of ".time_str($j->cached_time);
219
    page_tail();
220
}
221
222
function show_status_xml($x) {
223
    xml_header();
224
    echo "<server_status>\n<daemon_status>\n";
225
226
    $daemons = $x->daemons;
227
    foreach ($daemons->local_daemons as $d) {
228
        daemon_xml($d);
229
    }
230
    foreach ($daemons->remote_daemons as $d) {
231
        daemon_xml($d);
232
    }
233
    foreach ($daemons->disabled_daemons as $d) {
234
        daemon_xml($d);
235
    }
236
    echo "</daemon_status>\n<database_file_states>\n";
237
    $j = $x->jobs;
238
    item_xml("results_ready_to_send", $j->results_ready_to_send);
239
    item_xml("results_in_progress", $j->results_in_progress);
240
    item_xml("workunits_waiting_for_validation", $j->wus_need_validate);
241
    item_xml("workunits_waiting_for_assimilation", $j->wus_need_assimilate);
242
    item_xml("workunits_waiting_for_deletion", $j->wus_need_file_delete);
243
    item_xml("results_waiting_for_deletion", $j->results_need_file_delete);
244
    item_xml("transitioner_backlog_hours", $j->transitioner_backlog);
245
    item_xml("users_with_recent_credit", $j->users_with_recent_credit);
246
    item_xml("users_with_credit", $j->users_with_credit);
247
    item_xml("users_registered_in_past_24_hours", $j->users_past_24_hours);
248
    item_xml("hosts_with_recent_credit", $j->hosts_with_recent_credit);
249
    item_xml("hosts_with_credit", $j->hosts_with_credit);
250
    item_xml("hosts_registered_in_past_24_hours", $j->hosts_past_24_hours);
251
    item_xml("current_floating_point_speed", $j->flops);
252
    echo "<tasks_by_app>\n";
253
    foreach ($j->apps as $app) {
254
        echo "<app>\n";
255
        item_xml("id", $app->id);
256
        item_xml("name", $app->name);
257
        item_xml("unsent", $app->unsent);
258
        item_xml("in_progress", $app->in_progress);
259
        item_xml("avg_runtime", $app->info->avg);
260
        item_xml("min_runtime", $app->info->min);
261
        item_xml("max_runtime", $app->info->max);
262
        item_xml("users", $app->info->users);
263
        echo "</app>\n";
264
    }
265
    echo "</tasks_by_app>
266
</database_file_states>
267
</server_status>
268
";
269
}
270
271
function local_daemon_running($cmd, $pidname, $host) {
272
    if (!$pidname) {
273
        $cmd = trim($cmd);
274
        $x = explode(" ", $cmd);
275
        $prog = $x[0];
276
        $pidname = $prog . '.pid';
277
    }
278
    $path = "../../pid_$host/$pidname";
279
    if (is_file($path)) {
280
        $pid = file_get_contents($path);
281
        if ($pid) {
282
            $pid = trim($pid);
283
            $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...
284
            exec("ps -ww $pid", $out);
285
            foreach ($out as $y) {
286
                if (strstr($y, (string)$pid)) return 1;
287
            }
288
        }
289
    }
290
    return 0;
291
}
292
293
// returns a data structure of the form
294
// local_daemons: array of
295
//   cmd, status
296
// remote_daemons: array of
297
//   cmd, host, status
298
// disabled_daemons: array of
299
//   cmd, host
300
//
301
function get_daemon_status() {
302
    $c = simplexml_load_file("../../config.xml");
303
    if (!$c) {
0 ignored issues
show
introduced by
$c is of type SimpleXMLElement, thus it always evaluated to true.
Loading history...
304
        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...
305
    }
306
    $daemons = $c->daemons;
307
    $config = $c->config;
308
    $main_host = trim((string)$config->host);
309
    $master_url = trim((string)$config->master_url);
310
    $u = parse_url($master_url);
311
    if (!array_key_exists("host", $u)) {
312
        print_r($u);
313
        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...
314
    }
315
    $master_host = $u["host"];
316
    if ($config->www_host) {
317
        $web_host = trim((string) $config->www_host);
318
    } else {
319
        $web_host = $main_host;
320
    }
321
    if ($config->sched_host) {
322
        $sched_host = trim((string) $config->sched_host);
323
    } else {
324
        $sched_host = $main_host;
325
    }
326
    $have_remote = false;
327
    $local_daemons = array();
328
    $disabled_daemons = array();
329
330
    // the upload and download servers are sort of daemons too
331
    //
332
    $url = trim((string) $config->download_url);
333
    $u = parse_url($url);
334
    $h = $u["host"];
335
    if ($h == $master_host) {
336
        $y = new StdClass;
337
        $y->cmd = "Download server";
338
        $y->host = $h;
339
        $y->status = 1;
340
        $local_daemons[] = $y;
341
    } else {
342
        $have_remote = true;
343
    }
344
    $url = trim((string) $config->upload_url);
345
    $u = parse_url($url);
346
    $h = $u["host"];
347
    if ($h == $master_host) {
348
        $y = new StdClass;
349
        $y->cmd = "Upload server";
350
        $y->host = $h;
351
        $y->status = !file_exists("../../stop_upload");;
352
        $local_daemons[] = $y;
353
    } else {
354
        $have_remote = true;
355
    }
356
357
    // Scheduler is a daemon too
358
    //
359
    if ($sched_host == $main_host) {
360
        $y = new StdClass;
361
        $y->cmd = "Scheduler";
362
        $y->host = $sched_host;
363
        $y->status = !file_exists("../../stop_sched");;
364
        $local_daemons[] = $y;
365
    } else {
366
        $have_remote = true;
367
    }
368
369
    foreach ($daemons->daemon as $d) {
370
        if ((int)$d->disabled != 0) {
371
            $x = new StdClass;
372
            $x->cmd = (string)$d->cmd;
373
            $x->host = (string)$d->host;
374
            if (!$x->host) $x->host = $main_host;
375
            $x->status = -1;
376
            $disabled_daemons[] = $x;
377
            continue;
378
        }
379
        $host = $d->host?(string)$d->host:$main_host;
380
        if ($host != $web_host) {
381
            $have_remote = true;
382
            continue;
383
        }
384
        $x = new StdClass;
385
        $x->cmd = (string)$d->cmd;
386
        $x->status = local_daemon_running($x->cmd, trim($d->pid_file), $web_host);
387
        $x->host = $web_host;
388
        $local_daemons[] = $x;
389
390
    }
391
392
    $x = new StdClass;
393
    $x->local_daemons = $local_daemons;
394
    $x->disabled_daemons = $disabled_daemons;
395
    $x->missing_remote_status = false;
396
    $x->cached_time = 0;
397
    $x->remote_daemons = array();
398
    if ($have_remote) {
399
        $f = @file_get_contents("../cache/remote_server_status");
400
        if ($f) {
401
            $x->remote_daemons = unserialize($f);
402
            $x->cached_time = filemtime("../cache/remote_server_status");
403
        } else {
404
            $x->missing_remote_status = true;
405
        }
406
    }
407
    return $x;
408
}
409
410
function get_job_status() {
411
    $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 and null; however, parameter $data 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

411
    $s = unserialize(/** @scrutinizer ignore-type */ get_cached_data(STATUS_PAGE_TTL, "job_status"));
Loading history...
412
    if ($s) {
413
        return $s;
414
    }
415
416
    $s = new StdClass;
417
    $apps = BoincApp::enum("deprecated=0");
418
    foreach ($apps as $app) {
419
        $info = BoincDB::get()->lookup_fields("result", "stdClass",
420
            "ceil(avg(elapsed_time)/3600*100)/100 as avg,
421
            ceil(min(elapsed_time)/3600*100)/100 as min,
422
            ceil(max(elapsed_time)/3600*100)/100 as max,
423
            count(distinct userid) as users",
424
            "appid = $app->id
425
            AND validate_state=1
426
            AND received_time > (unix_timestamp()-86400)
427
            "
428
        );
429
        // $info fields will be null if app has no results
430
        if ($info->avg) {
431
            $app->info = $info;
432
        } else {
433
            $app->info = null;
434
        }
435
        $app->unsent = BoincResult::count("appid=$app->id and server_state=2");
436
        $app->in_progress = BoincResult::count("appid=$app->id and server_state=4");
437
    }
438
    $s->apps = $apps;
439
    $s->results_ready_to_send = BoincResult::count("server_state=2");
440
    $s->results_in_progress = BoincResult::count("server_state=4");
441
    $s->results_need_file_delete = BoincResult::count("file_delete_state=1");
442
    $s->wus_need_validate = BoincWorkunit::count("need_validate=1");
443
    $s->wus_need_assimilate = BoincWorkunit::count("assimilate_state=1");
444
    $s->wus_need_file_delete = BoincWorkunit::count("file_delete_state=1");
445
    $x = BoincDB::get()->lookup_fields("workunit", "stdClass", "MIN(transition_time) as min", "TRUE");
446
    $gap = (time() - $x->min)/3600;
447
    if (($gap < 0) || ($x->min == 0)) {
448
        $gap = 0;
449
    }
450
    $s->transitioner_backlog = $gap;
451
    $s->users_with_recent_credit = BoincUser::count("expavg_credit>1");
452
    $s->users_with_credit = BoincUser::count("total_credit>1");
453
    $s->users_past_24_hours = BoincUser::count("create_time > (unix_timestamp() - 86400)");
454
    $s->hosts_with_recent_credit = BoincHost::count("expavg_credit>1");
455
    $s->hosts_with_credit = BoincHost::count("total_credit>1");
456
    $s->hosts_past_24_hours = BoincHost::count("create_time > (unix_timestamp() - 86400)");
457
    $s->flops = BoincUser::sum("expavg_credit")/200;
458
459
    $s->db_revision = null;
460
    if (file_exists("../../db_revision")) {
461
        $s->db_revision = trim(file_get_contents("../../db_revision"));
462
    }
463
464
    $s->cached_time = time();
465
    $e = set_cached_data(STATUS_PAGE_TTL, serialize($s), "job_status");
466
    if ($e) echo "set_cached_data(): $e\n";
467
    return $s;
468
}
469
470
function show_counts_xml() {
471
    xml_header();
472
    echo "<job_counts>\n";
473
    item_xml('results_ready_to_send', BoincResult::count("server_state=2"));
474
    item_xml('results_in_progress', BoincResult::count("server_state=4"));
475
    item_xml('results_need_file_delete', BoincResult::count("file_delete_state=1"));
476
    item_xml('wus_need_validate', BoincWorkunit::count("need_validate=1"));
477
    item_xml('wus_need_assimilate', BoincWorkunit::count("assimilate_state=1"));
478
    item_xml('wus_need_file_delete', BoincWorkunit::count("file_delete_state=1"));
479
    echo "</job_counts>\n";
480
}
481
482
function main() {
483
    if (get_int('counts', true)) {
484
        show_counts_xml();
485
    } else {
486
        $x = new StdClass;
487
        $x->daemons = get_daemon_status();
488
        $x->jobs = get_job_status();
489
        if (get_int('xml', true)) {
490
            show_status_xml($x);
491
        } else {
492
            show_status_html($x);
493
        }
494
    }
495
}
496
497
main();
498
?>
499