AlertRules::runRules()   F
last analyzed

Complexity

Conditions 24
Paths 483

Size

Total Lines 96
Code Lines 69

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 69
dl 0
loc 96
rs 0.718
c 0
b 0
f 0
cc 24
nc 483
nop 1

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
/**
3
 * AlertRules.php
4
 *
5
 * Extending the built in logging to add an event logger function
6
 *
7
 * This program is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation, either version 3 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19
 *
20
 * Original Code:
21
 *
22
 * @author Daniel Preussker <[email protected]>
23
 * @copyright 2014 f0o, LibreNMS
24
 * @license GPL
25
 *
26
 * @link       https://www.librenms.org
27
 *
28
 * @copyright  2019 KanREN, Inc.
29
 * @author     Heath Barnhart <[email protected]>
30
 */
31
32
namespace LibreNMS\Alert;
33
34
use Carbon\Carbon;
35
use LibreNMS\Enum\AlertState;
36
37
class AlertRules
38
{
39
    public function runRules($device_id)
40
    {
41
42
        //Check to see if under maintenance
43
        if (AlertUtil::isMaintenance($device_id) > 0) {
44
            echo "Under Maintenance, skipping alert rules check.\r\n";
45
46
            return false;
47
        }
48
        //Check to see if disable alerting is set
49
        if (AlertUtil::hasDisableNotify($device_id)) {
50
            echo "Disable alerting is set, Clearing active alerts and skipping alert rules check\r\n";
51
            $device_alert['state'] = AlertState::CLEAR;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$device_alert was never initialized. Although not strictly required by PHP, it is generally a good practice to add $device_alert = array(); before regardless.
Loading history...
52
            $device_alert['alerted'] = 0;
53
            $device_alert['open'] = 0;
54
            dbUpdate($device_alert, 'alerts', '`device_id` = ?', [$device_id]);
55
56
            return false;
57
        }
58
        //Checks each rule.
59
        foreach (AlertUtil::getRules($device_id) as $rule) {
60
            c_echo('Rule %p#' . $rule['id'] . ' (' . $rule['name'] . '):%n ');
61
            $extra = json_decode($rule['extra'], true);
62
            if (isset($extra['invert'])) {
63
                $inv = (bool) $extra['invert'];
64
            } else {
65
                $inv = false;
66
            }
67
            d_echo(PHP_EOL);
68
            if (empty($rule['query'])) {
69
                $rule['query'] = AlertDB::genSQL($rule['rule'], $rule['builder']);
70
            }
71
            $sql = $rule['query'];
72
            $qry = dbFetchRows($sql, [$device_id]);
73
            $cnt = count($qry);
74
            for ($i = 0; $i < $cnt; $i++) {
75
                if (isset($qry[$i]['ip'])) {
76
                    $qry[$i]['ip'] = inet6_ntop($qry[$i]['ip']);
77
                }
78
            }
79
            $s = sizeof($qry);
80
            if ($s == 0 && $inv === false) {
81
                $doalert = false;
82
            } elseif ($s > 0 && $inv === false) {
83
                $doalert = true;
84
            } elseif ($s == 0 && $inv === true) {
85
                $doalert = true;
86
            } else {
87
                $doalert = false;
88
            }
89
90
            $current_state = dbFetchCell('SELECT state FROM alerts WHERE rule_id = ? AND device_id = ? ORDER BY id DESC LIMIT 1', [$rule['id'], $device_id]);
91
            if ($doalert) {
92
                if ($current_state == AlertState::ACKNOWLEDGED) {
93
                    c_echo('Status: %ySKIP');
94
                } elseif ($current_state >= AlertState::ACTIVE) {
95
                    c_echo('Status: %bNOCHG');
96
                    // NOCHG here doesn't mean no change full stop. It means no change to the alert state
97
                    // So we update the details column with any fresh changes to the alert output we might have.
98
                    $alert_log = dbFetchRow('SELECT alert_log.id, alert_log.details FROM alert_log,alert_rules WHERE alert_log.rule_id = alert_rules.id && alert_log.device_id = ? && alert_log.rule_id = ? && alert_rules.disabled = 0
99
     ORDER BY alert_log.id DESC LIMIT 1', [$device_id, $rule['id']]);
100
                    $details = [];
101
                    if (! empty($alert_log['details'])) {
102
                        $details = json_decode(gzuncompress($alert_log['details']), true);
103
                    }
104
                    $details['contacts'] = AlertUtil::getContacts($qry);
105
                    $details['rule'] = $qry;
106
                    $details = gzcompress(json_encode($details), 9);
107
                    dbUpdate(['details' => $details], 'alert_log', 'id = ?', [$alert_log['id']]);
108
                } else {
109
                    $extra = gzcompress(json_encode(['contacts' => AlertUtil::getContacts($qry), 'rule'=>$qry]), 9);
110
                    if (dbInsert(['state' => AlertState::ACTIVE, 'device_id' => $device_id, 'rule_id' => $rule['id'], 'details' => $extra], 'alert_log')) {
111
                        if (is_null($current_state)) {
112
                            dbInsert(['state' => AlertState::ACTIVE, 'device_id' => $device_id, 'rule_id' => $rule['id'], 'open' => 1, 'alerted' => 0], 'alerts');
113
                        } else {
114
                            dbUpdate(['state' => AlertState::ACTIVE, 'open' => 1, 'timestamp' => Carbon::now()], 'alerts', 'device_id = ? && rule_id = ?', [$device_id, $rule['id']]);
115
                        }
116
                        c_echo(PHP_EOL . 'Status: %rALERT');
117
                    }
118
                }
119
            } else {
120
                if (! is_null($current_state) && $current_state == AlertState::RECOVERED) {
121
                    c_echo('Status: %bNOCHG');
122
                } else {
123
                    if (dbInsert(['state' => AlertState::RECOVERED, 'device_id' => $device_id, 'rule_id' => $rule['id']], 'alert_log')) {
124
                        if (is_null($current_state)) {
125
                            dbInsert(['state' => AlertState::RECOVERED, 'device_id' => $device_id, 'rule_id' => $rule['id'], 'open' => 1, 'alerted' => 0], 'alerts');
126
                        } else {
127
                            dbUpdate(['state' => AlertState::RECOVERED, 'open' => 1, 'note' => '', 'timestamp' => Carbon::now()], 'alerts', 'device_id = ? && rule_id = ?', [$device_id, $rule['id']]);
128
                        }
129
130
                        c_echo(PHP_EOL . 'Status: %gOK');
131
                    }
132
                }
133
            }
134
            c_echo('%n' . PHP_EOL);
135
        }
136
    }
137
}
138