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 0
Metric Value
cc 12
eloc 89
nc 1024
nop 1
dl 0
loc 112
rs 2.48
c 0
b 0
f 0

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

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