File: nut

package info (click to toggle)
logwatch 7.14-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,572 kB
  • sloc: perl: 8,290; sh: 354; makefile: 38
file content (314 lines) | stat: -rw-r--r-- 12,646 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
########################################################
# Please file all bug reports, patches, and feature
# requests under:
#      https://sourceforge.net/p/logwatch/_list/tickets
# Help requests and discusion can be filed under:
#      https://sourceforge.net/p/logwatch/discussion/
########################################################

########################################################
## Copyright (c) 2019-2022 Orion Poplawski
## Covered under the included MIT/X-Consortium License:
##    http://www.opensource.org/licenses/mit-license.php
## All modifications and contributions by other persons to
## this script are assumed to have been donated to the
## Logwatch project and thus assume the above copyright
## and licensing terms.  If you want to make contributions
## under your own copyright or a different license this
## must be explicitly stated in the contribution an the
## Logwatch project reserves the right to not accept such
## contributions.  If you have made significant
## contributions to this script and want to claim
## copyright please contact logwatch-devel@lists.sourceforge.net.
#########################################################

use strict;
use warnings;
my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0;
my ($Hostname) = ($ENV{'HOSTNAME'} =~ /^([^.]+)/);
my $CannotConnectThreshold = $ENV{'cannot_connect_threshold'} || 0;
my %BatteryLow;
my %BatteryReplace;
my %CannotConnect;
my %Commands;
my %CommunicationLost;
my %CommunicationState;
my %Connected;
my %ConnectionFailure;
my %DataStale;
my %DataStaleState;
my %Logins;
my %OnBattery;
my %State;
my %OtherList;
my %Unavailable;
my $SelfTestPassed = 0;
my $SelfTestFailed = 0;
my $UpsdrvctlMessages;

while (defined(my $ThisLine = <STDIN>)) {
   chomp($ThisLine);
   # Strip PID
   $ThisLine =~ s/^([^[]+)\[\d+\]:/$1:/;

   my $ups;
   my $state;
   my $user;
   my $command;

   if ($ThisLine =~ /^(?:nut-server|upsd): User .* logged out/
       # CUPS matches our generous service regex
       or $ThisLine =~ /^cupsd:/
       or $ThisLine =~ /: Could not find PID file/
       # TODO - count start/stops
       or $ThisLine =~ /: Running as foreground process/
       or $ThisLine =~ /Signal 15: exiting/
       or $ThisLine =~ /Startup successful/
       or $ThisLine =~ /^upsdrvctl: Detected .* on host /
       or $ThisLine =~ /^upsdrvctl: Network UPS Tools - /
       or $ThisLine =~ /^upsdrvctl: USB communication driver/
       or $ThisLine =~ /^upsdrvctl: Using subdriver:/
       or $ThisLine =~ /^upsdrvctl: using '.*' to set battery low state/
       or $ThisLine =~ /^(?:nut-server|upsd): \/etc\/pki\/nssdb is world readable/
       # TODO - Report at high detail level
       or $ThisLine =~ /^(?:nut-server|upsd): Found \d+ UPS defined in ups.conf/
       or $ThisLine =~ /^(?:nut-server|upsd): Intend to retrieve password for NSS User Private Key and Certificate Services \/ NSS Certificate DB: password configured/
       or $ThisLine =~ /^(?:nut-server|upsd): Limit\s*Soft Limit/
       or $ThisLine =~ /^(?:nut-server|upsd): listening on /
       or $ThisLine =~ /^(?:nut-server|upsd): mainloop: Interrupted system call/
       or $ThisLine =~ /^(?:nut-server|upsd): Max open files/
       or $ThisLine =~ /^(?:nut-server|upsd): Network UPS Tools upsd/
       or $ThisLine =~ /^(?:nut-server|upsd): fopen \S+\/upsd.pid: No such file or directory/
       or $ThisLine =~ /^(?:nut-server|upsd): SSL handshake done successfully with client/
       or $ThisLine =~ /^(?:nut-monitor|upsmon): Connected to/
       or $ThisLine =~ /^(?:nut-monitor|upsmon): Connecting in SSL to/
       or $ThisLine =~ /^(?:nut-monitor|upsmon): Certificate verification is disabled/
       or $ThisLine =~ /^(?:nut-monitor|upsmon): Do not intend to authenticate server/
       or $ThisLine =~ /^(?:nut-monitor|upsmon): fopen \S+\/upsmon.pid: No such file or directory/
       or $ThisLine =~ /^(?:nut-monitor|upsmon): Init SSL without certificate database/
       or $ThisLine =~ /^(?:nut-monitor|upsmon): Network UPS Tools upsmon/
       # This will generate a communication lost message - TODO - track reasons?
       or $ThisLine =~ /^(?:nut-monitor|upsmon): Poll UPS \[(\S+)\] failed -/
       or $ThisLine =~ /^(?:nut-monitor|upsmon): SSL handshake done successfully with server/
       or $ThisLine =~ /^(?:nut-monitor|upsmon): UPS: \S+ \((?:master:primary)\)/
       or $ThisLine =~ /^(?:nut-monitor|upsmon): UPS: \S+ \((?:slave:secondary)\)/
       or $ThisLine =~ /^(?:nut-monitor|upsmon): Using power down flag file/
       # This is going away - https://bugzilla.redhat.com/show_bug.cgi?id=1608176
       or $ThisLine =~ /^(?:nut-monitor|upsmon): wall: cannot get tty name: Inappropriate ioctl for device/
       or $ThisLine =~ /^(?:nut-monitor|nut-server): upsnotify: failed to notify about state 2: no notification tech defined, will not spam more about it/
       or $ThisLine =~ /^(?:nut-monitor|nut-server): upsnotify: logged the systemd watchdog situation once, will not spam more about it/
       or $ThisLine =~ /^upssched: (?:Cancelling|New) timer:/
       or $ThisLine =~ /^upssched: Timer daemon started/
       or $ThisLine =~ /^upssched: Timer queue empty/
       or $ThisLine =~ /^snmp-ups: \[(\S+)\] snmp_ups_walk: data (:?resumed|stale)/
       or $ThisLine =~ /^UPS: No longer on battery power/
       # Should get a particular ups on battery power message
       or $ThisLine =~ /^UPS: On battery power in response to an input power problem/
       or $ThisLine =~ /^UPS: UPS: Restored the local network management interface-to-UPS communication/
       or $ThisLine =~ /^UPS: Started a self-test/
      ) {
     # Ignore these
   } elsif (($ups) = ($ThisLine =~ /^(?:nut-monitor|upsmon): UPS (\S+) battery is low/)) {
      $BatteryLow{$ups}++;
   } elsif (($ups) = ($ThisLine =~ /^(?:nut-monitor|upsmon): UPS (\S+) battery needs to be replaced/)) {
      $BatteryReplace{$ups}++;
   } elsif (($ups) = ($ThisLine =~ /^(?:nut-server|upsd): Can't connect to UPS \[(\S+)\]/)) {
      $CannotConnect{$ups}++;
   } elsif (($user, $command, $ups) = ($ThisLine =~ /^(?:nut-server|upsd): Instant command: (\S+) did (\S+) on (\S+)/)) {
      $Commands{$ups}->{$user}->{$command}++;
   } elsif (($ups) = ($ThisLine =~ /^(?:nut-server|upsd): Connected to UPS \[(\S+)\]/)) {
      $Connected{$ups}++;
   } elsif (($ups) = ($ThisLine =~ /^(?:nut-monitor|upsmon): Communications with UPS (\S+) lost/)) {
      $CommunicationLost{$ups}++;
      $CommunicationState{$ups} = "lost";
   } elsif (($ups) = ($ThisLine =~ /^(?:nut-monitor|upsmon): Communications with UPS (\S+) established/)) {
      $CommunicationState{$ups} = "established";
      # At Detail 0, we don't want to know about recovered disconnects
      if ($Detail == 0) {
         $Unavailable{$ups}--;
         delete $Unavailable{$ups} if $Unavailable{$ups} <= 0;
      }
   # This may always be paired with the "unavailable" message below - so may want to ignore or move to higher detail
   } elsif (($ups) = ($ThisLine =~ /^(?:nut-monitor|upsmon): UPS \[(.+)\]: connect failed:/)) {
      $ConnectionFailure{$ups}++;
   } elsif (($ups) = ($ThisLine =~ /^(?:nut-monitor|upsmon): UPS (.+)\ is unavailable/)) {
      $Unavailable{$ups}++;
   } elsif (($ups, $state) = ($ThisLine =~ /^(?:nut-monitor|upsmon): UPS (\S+) on (.*)/)) {
      my ($host) = ($ups =~ /@([^.]+)/);
      next unless $host eq "localhost" or $host eq $Hostname;
      $State{$ups} = $state;
      $OnBattery{$ups}++ if $state eq "battery";
   } elsif (($ups, $state) = ($ThisLine =~ /^(?:nut-monitor|upsmon): UPS: (\S+) \(\S+\) \((.*)\)/)) {
      my ($host) = ($ups =~ /@([^.]+)/);
      next unless $host eq "localhost" or $host eq $Hostname;
      $State{$ups} = $state;
      #$OnBattery{$ups}++ if $state eq "battery";
   } elsif (($ups) = ($ThisLine =~ /^(?:nut-server|upsd): Data for UPS \[(\S+)\] is stale/)) {
      $DataStale{$ups}++;
      $DataStaleState{$ups}++;
   } elsif (($ups) = ($ThisLine =~ /^(?:nut-server|upsd): UPS \[(\S+)\] data is no longer stale/)) {
      $DataStaleState{$ups}--;
   } elsif (($user, $ups) = ($ThisLine =~ /^(?:nut-server|upsd): User (\S+) logged into UPS \[(\S+)\]/)) {
      $Logins{$user}->{$ups}++;
   } elsif (my ($msg) = ($ThisLine =~ /^upsdrvctl: (.*)/)) {
      $UpsdrvctlMessages .= "   $msg\n";
   } elsif ($ThisLine =~ /^UPS: Passed a self-test/) {
      $SelfTestPassed++;
   }  else {
      $OtherList{$ThisLine}++;
   }
}

if (keys %BatteryReplace) {
   print "WARNING: UPS battery needs to be replaced:\n";
   foreach my $ups (sort {$a cmp $b} keys %BatteryReplace) {
      print "   $ups: $BatteryReplace{$ups} Time(s)\n";
   }
   print "\n";
}

if (keys %CannotConnect) {
   my $first = 1;
   foreach my $ups (sort {$a cmp $b} keys %CannotConnect) {
      if ($CannotConnect{$ups} >= $CannotConnectThreshold) {
         if ($first) {
            print "Cannot connect to UPS:\n";
            print " (with threshold >= $CannotConnectThreshold)" if $CannotConnectThreshold;
            print "\n";
            $first = 0;
         }
         print "   $ups: $CannotConnect{$ups} Time(s)\n";
      }
   }
   print "\n";
}

if (keys %ConnectionFailure) {
   my $first = 1;
   foreach my $ups (sort {$a cmp $b} keys %ConnectionFailure) {
      if ($ConnectionFailure{$ups} >= $CannotConnectThreshold) {
         if ($first) {
            print "Cannot connect to UPS server:\n";
            print " (with threshold >= $CannotConnectThreshold)" if $CannotConnectThreshold;
            print "\n";
            $first = 0;
         }
         print "   $ups: $ConnectionFailure{$ups} Time(s)\n";
      }
   }
   print "\n";
}

if (keys %Unavailable) {
   print "UPS is unavailable:\n";
   foreach my $ups (sort {$a cmp $b} keys %Unavailable) {
      print "   $ups: $Unavailable{$ups} Time(s)\n";
   }
   print "\n";
}

if ($UpsdrvctlMessages) {
   print "upsdrvctl Messages:\n";
   print $UpsdrvctlMessages;
}

if (keys %BatteryLow) {
   print "UPS battery low:\n";
   foreach my $ups (sort {$a cmp $b} keys %BatteryLow) {
      print "   $ups: $BatteryLow{$ups} Time(s)\n";
   }
   print "\n";
}

if (keys %OnBattery) {
   print "UPS on battery:\n";
   foreach my $ups (sort {$a cmp $b} keys %OnBattery) {
      print "   $ups: $OnBattery{$ups} Time(s)\n";
   }
   print "\n";
}

# TODO - Alert if too many disconnects?
my $CommunicationLostCurrent = 0;
foreach my $ups (keys %CommunicationLost) {
   $CommunicationLostCurrent += 1 if $CommunicationState{$ups} eq "lost";
}

if (keys %CommunicationLost and ($Detail or $CommunicationLostCurrent)) {
   print "Communication lost:\n";
   foreach my $ups (sort {$a cmp $b} keys %CommunicationLost) {
      print "   $ups: $CommunicationLost{$ups} Time(s)";
      print " * Currently " . $CommunicationState{$ups};
      print "\n";
   }
   print "\n";
}

# TODO - Alert if too many?
my $DataStaleStateTotal = 0;
foreach my $ups (keys %DataStale) {
   $DataStaleStateTotal += $DataStaleState{$ups};
}

if (keys %DataStale and ($Detail or $DataStaleStateTotal)) {
   print "Data is stale:\n";
   foreach my $ups (sort {$a cmp $b} keys %DataStale) {
      print "   $ups: $DataStale{$ups} Time(s)";
      print " * Currently stale" if $DataStaleState{$ups};
      print "\n";
   }
   print "\n";
}

if ($SelfTestPassed and ($Detail >= 5)) {
   print "UPS Self-Test Passed $SelfTestPassed Time(s)\n\n";
}

if (keys %Connected and ($Detail >= 5)) {
   print "Connected to UPS:\n";
   foreach my $ups (sort {$a cmp $b} keys %Connected) {
      print "   $ups: $Connected{$ups} Time(s)\n";
   }
   print "\n";
}

if (keys %Commands and $Detail) {
   print "Commands run:\n";
   foreach my $ups (sort {$a cmp $b} keys %Commands) {
      print "   UPS $ups:\n";
      foreach my $user (sort {$a cmp $b} keys %{$Commands{$ups}}) {
         print "      User $user:\n";
         foreach my $command (sort {$a cmp $b} keys %{$Commands{$ups}{$user}}) {
            print "         $command: $Commands{$ups}->{$user}->{$command} Time(s)\n";
         }
      }
   }
   print "\n";
}

if (keys %Logins and ($Detail >= 10)) {
   print "Logins:\n";
   foreach my $user (sort {$a cmp $b} keys %Logins) {
      print "   $user:\n";
      foreach my $ups (sort {$a cmp $b} keys %{$Logins{$user}}) {
         print "      $ups: $Logins{$user}{$ups} Time(s)\n";
      }
   }
   print "\n";
}

if (keys %OtherList) {
   print "\n\n**Unmatched Entries**\n";
   foreach my $line (sort {$a cmp $b} keys %OtherList) {
      print "   $line: $OtherList{$line} Time(s)\n";
   }
}

exit(0);

# vi: shiftwidth=3 tabstop=3 syntax=perl et
# Local Variables:
# mode: perl
# perl-indent-level: 3
# indent-tabs-mode: nil
# End: