]> git.proxmox.com Git - pmg-api.git/blame - PMG/CLI/pmgreport.pm
fix typos
[pmg-api.git] / PMG / CLI / pmgreport.pm
CommitLineData
3dfe317a
DM
1package PMG::CLI::pmgreport;
2
3use strict;
4use Data::Dumper;
5use Template;
6use POSIX qw(strftime);
7
8use PVE::INotify;
9use PVE::CLIHandler;
10
11use PMG::Utils;
12use PMG::Config;
13use PMG::RESTEnvironment;
308c2bfc 14
3dfe317a 15use PMG::API2::Nodes;
308c2bfc
DM
16use PMG::ClusterConfig;
17use PMG::Cluster;
18use PMG::API2::Cluster;
02251e49
DM
19use PMG::RuleDB;
20use PMG::Statistic;
3dfe317a
DM
21
22use base qw(PVE::CLIHandler);
23
24my $nodename = PVE::INotify::nodename();
25
26sub setup_environment {
27 PMG::RESTEnvironment->setup_default_cli_env();
308c2bfc
DM
28
29 my $rpcenv = PMG::RESTEnvironment->get();
30 # API /config/cluster/nodes need a ticket to connect to other nodes
31 my $ticket = PMG::Ticket::assemble_ticket('root@pam');
32 $rpcenv->set_ticket($ticket);
3dfe317a
DM
33}
34
35my $get_system_table_data = sub {
36
37 my $ni = PMG::API2::NodeInfo->status({ node => $nodename });
38
39 my $data = [];
40
41 push @$data, { text => 'Hostname', value => $nodename };
42
43 my $uptime = $ni->{uptime} ? PMG::Utils::format_uptime($ni->{uptime}) : '-';
44
45 push @$data, { text => 'Uptime', value => $uptime };
46
47 push @$data, { text => 'Version', value => $ni->{pmgversion} };
48
49 my $loadavg15 = '-';
50 if (my $d = $ni->{loadavg}) {
308c2bfc 51 $loadavg15 = sprintf("%.2f", $d->[2]);
3dfe317a
DM
52 }
53 push @$data, { text => 'Load', value => $loadavg15 };
54
55 my $mem = '-';
56 if (my $d = $ni->{memory}) {
57 $mem = sprintf("%.2f%%", $d->{used}*100/$d->{total});
58 }
59 push @$data, { text => 'Memory', value => $mem };
60
61 my $disk = '-';
62 if (my $d = $ni->{rootfs}) {
63 $disk = sprintf("%.2f%%", $d->{used}*100/$d->{total});
64 }
65 push @$data, { text => 'Disk', value => $disk };
66
67 return $data
68};
69
308c2bfc
DM
70my $get_cluster_table_data = sub {
71
72 my $res = PMG::API2::Cluster->status({});
73 return undef if !scalar(@$res);
74
75 my $data = [];
76
77 foreach my $ni (@$res) {
78 my $state = 'A';
79 $state = 'S' if !$ni->{insync};
80
81 my $loadavg1 = '-';
82 if (my $d = $ni->{loadavg}) {
83 $loadavg1 = sprintf("%.2f", $d->[0]);
84 }
85
86 my $memory = '-';
87 if (my $d = $ni->{memory}) {
88 $memory = sprintf("%.2f%%", $d->{used}*100/$d->{total});
89 }
90
91 my $disk = '-';
92 if (my $d = $ni->{rootfs}) {
93 $disk = sprintf("%.2f%%", $d->{used}*100/$d->{total});
94 }
95
96 push @$data, {
97 hostname => $ni->{name},
98 ip => $ni->{ip},
99 type => $ni->{type},
100 state => $state,
101 loadavg1 => $loadavg1,
102 memory => $memory,
103 disk => $disk,
104 };
105 };
106
107 return $data;
108};
3dfe317a 109
30898745
DM
110my $get_incoming_table_data = sub {
111 my ($totals) = @_;
112
113 my $data = [];
114
115 push @$data, {
116 text => 'Incoming Mails',
117 value => $totals->{count_in},
118 percentage => $totals->{count_in_per},
119 };
120
121 push @$data, {
122 text => 'Spam Mails',
123 value => $totals->{spamcount_in},
124 percentage => $totals->{spamcount_in_per},
125 };
126
127 push @$data, {
128 text => 'Virus Mails',
129 value => $totals->{viruscount_in},
130 percentage => $totals->{viruscount_in_per},
131 };
132
133 push @$data, {
134 text => 'SPF rejects',
135 value => $totals->{spfcount},
136 percentage => $totals->{spfcount_per},
137 };
138
139 push @$data, {
140 text => 'Mail Traffic',
141 value => sprintf ("%.3f MByte", $totals->{traffic_in}),
142 };
143
144 return $data;
145};
146
147my $get_outgoing_table_data = sub {
148 my ($totals) = @_;
149
150 my $data = [];
151
152 push @$data, {
153 text => 'Outgoing Mails',
154 value => $totals->{count_out},
155 percentage => $totals->{count_out_per},
156 };
157
158 push @$data, {
159 text => 'Bounces',
160 value => $totals->{bounces_out},
161 percentage => $totals->{bounces_out_per},
162 };
163
164 push @$data, {
165 text => 'Mail Traffic',
166 value => sprintf ("%.3f MByte", $totals->{traffic_out}),
167 };
168
169 return $data;
170};
171
d68581ee
DM
172my $get_virus_table_data = sub {
173 my ($virusinfo) = @_;
174
175 my $data = [];
176
177 foreach my $entry (@$virusinfo) {
178 next if !$entry->{count};
179 last if scalar(@$data) >= 10;
180 push @$data, { name => $entry->{name}, count => $entry->{count} };
181 }
182
183 return undef if !scalar(@$data);
184
185 return $data;
186};
187
68b5b6c1
DM
188my $get_quarantine_table_data = sub {
189 my ($dbh, $qtype) = @_;
190
191 # Note;: We try to estimate used disk space - each mail
192 # is stored in an extra file ...
193
194 my $bs = 4096;
195
196 my $sth = $dbh->prepare(
197 "SELECT count(ID) as count, sum (ceil((Bytes+$bs-1)/$bs)*$bs) / (1024*1024) as mbytes, " .
198 "avg(Bytes) as avgbytes, avg(Spamlevel) as avgspam " .
199 "FROM CMailStore WHERE QType = ?");
200
201 $sth->execute($qtype);
202
203 my $ref = $sth->fetchrow_hashref();
204
205 $sth->finish;
206
207 return undef if !($ref && $ref->{count});
208
209 my $data = [];
210
211 push @$data, {
212 text => "Quarantine Size (MBytes)",
213 value => int($ref->{mbytes}),
214 };
215
216 push @$data, {
217 text => "Number of Mails",
218 value => $ref->{count},
219 };
220
221 push @$data, {
222 text => "Average Size (Bytes)",
223 value => int($ref->{avgbytes}),
224 };
225
226 if ($qtype eq 'S') {
227 push @$data, {
228 text => "Average Spam Level",
229 value => int($ref->{avgspam}),
230 };
231 }
232
233 return $data;
234};
235
3dfe317a
DM
236__PACKAGE__->register_method ({
237 name => 'pmgreport',
238 path => 'pmgreport',
239 method => 'POST',
240 description => "Generate and send daily system report email.",
241 parameters => {
242 additionalProperties => 0,
308c2bfc
DM
243 properties => {
244 debug => {
245 description => "Debug mode. Print raw email to stdout instead of sending them.",
246 type => 'boolean',
247 optional => 1,
248 default => 0,
249 },
250 auto => {
251 description => "Auto mode. Use setting from system configuration (set when invoked fron cron).",
252 type => 'boolean',
253 optional => 1,
254 default => 0,
255 },
256 receiver => {
257 description => "Send report to this email address. Default is the administratior email address.",
258 type => 'string', format => 'email',
259 optional => 1,
260 },
2f7031b7
DM
261 timespan => {
262 description => "Select time span for included email statistics.\n\nNOTE: System and cluster performance data is always from current time (when script is run).",
263 type => 'string',
264 enum => ['today', 'yesterday'],
265 default => 'today',
266 optional => 1,
267 },
308c2bfc 268 },
3dfe317a
DM
269 },
270 returns => { type => 'null'},
271 code => sub {
272 my ($param) = @_;
273
2f7031b7
DM
274 my $timespan = $param->{timespan} // 'today';
275 my ($start, $end) = PMG::Utils::lookup_timespan($timespan);
3dfe317a 276
2f7031b7 277 my $fqdn = PVE::Tools::get_fqdn($nodename);
3dfe317a
DM
278
279 my $vars = {
280 hostname => $nodename,
281 fqdn => $fqdn,
282 date => strftime("%F", localtime($end - 1)),
283 };
284
308c2bfc
DM
285 my $cinfo = PMG::ClusterConfig->new();
286 my $role = $cinfo->{local}->{type} // '-';
287
288 if ($role eq '-') {
289 $vars->{system} = $get_system_table_data->();
290 } else {
291 $vars->{cluster} = $get_cluster_table_data->();
292 if ($role eq 'master') {
293 # OK
294 } else {
295 return undef if $param->{auto}; # silent exit - do not send report
296 }
297 }
3dfe317a 298
02251e49
DM
299
300 my $stat = PMG::Statistic->new ($start, $end);
301 my $rdb = PMG::RuleDB->new();
302
303 # update statistics
304 PMG::Statistic::update_stats($rdb->{dbh}, $cinfo);
305
306 my $totals = $stat->total_mail_stat($rdb);
02251e49 307
30898745 308 $vars->{incoming} = $get_incoming_table_data->($totals);
02251e49 309
30898745 310 $vars->{outgoing} = $get_outgoing_table_data->($totals);
02251e49 311
d68581ee
DM
312 my $virusinfo = $stat->total_virus_stat ($rdb);
313 if (my $data = $get_virus_table_data->($virusinfo)) {
314 $vars->{virusstat} = $data;
315 }
316
68b5b6c1
DM
317 if (my $data = $get_quarantine_table_data->($rdb->{dbh}, 'V')) {
318 $vars->{virusquar} = $data;
319 }
320
321 if (my $data = $get_quarantine_table_data->($rdb->{dbh}, 'S')) {
322 $vars->{spamquar} = $data;
323 }
324
3dfe317a
DM
325 my $tt = PMG::Config::get_template_toolkit();
326
327 my $cfg = PMG::Config->new();
308c2bfc 328 my $email = $param->{receiver} // $cfg->get ('admin', 'email');
3dfe317a
DM
329
330 if (!defined($email)) {
308c2bfc
DM
331 return undef if $param->{auto}; # silent exit - do not send report
332 die "no receiver configured\n";
3dfe317a
DM
333 }
334
335 my $mailfrom = "Proxmox Mail Gateway <postmaster>";
336 PMG::Utils::finalize_report($tt, 'pmgreport.tt', $vars, $mailfrom, $email, $param->{debug});
337
338 return undef;
339 }});
340
341our $cmddef = [ __PACKAGE__, 'pmgreport', [], undef ];
342
3431;