]>
Commit | Line | Data |
---|---|---|
3dfe317a DM |
1 | package PMG::CLI::pmgreport; |
2 | ||
3 | use strict; | |
4 | use Data::Dumper; | |
5 | use Template; | |
6 | use POSIX qw(strftime); | |
7 | ||
8 | use PVE::INotify; | |
9 | use PVE::CLIHandler; | |
10 | ||
11 | use PMG::Utils; | |
12 | use PMG::Config; | |
13 | use PMG::RESTEnvironment; | |
308c2bfc | 14 | |
3dfe317a | 15 | use PMG::API2::Nodes; |
308c2bfc DM |
16 | use PMG::ClusterConfig; |
17 | use PMG::Cluster; | |
18 | use PMG::API2::Cluster; | |
02251e49 DM |
19 | use PMG::RuleDB; |
20 | use PMG::Statistic; | |
3dfe317a DM |
21 | |
22 | use base qw(PVE::CLIHandler); | |
23 | ||
24 | my $nodename = PVE::INotify::nodename(); | |
25 | ||
26 | sub 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 | ||
35 | my $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 |
70 | my $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 DM |
109 | |
110 | __PACKAGE__->register_method ({ | |
111 | name => 'pmgreport', | |
112 | path => 'pmgreport', | |
113 | method => 'POST', | |
114 | description => "Generate and send daily system report email.", | |
115 | parameters => { | |
116 | additionalProperties => 0, | |
308c2bfc DM |
117 | properties => { |
118 | debug => { | |
119 | description => "Debug mode. Print raw email to stdout instead of sending them.", | |
120 | type => 'boolean', | |
121 | optional => 1, | |
122 | default => 0, | |
123 | }, | |
124 | auto => { | |
125 | description => "Auto mode. Use setting from system configuration (set when invoked fron cron).", | |
126 | type => 'boolean', | |
127 | optional => 1, | |
128 | default => 0, | |
129 | }, | |
130 | receiver => { | |
131 | description => "Send report to this email address. Default is the administratior email address.", | |
132 | type => 'string', format => 'email', | |
133 | optional => 1, | |
134 | }, | |
2f7031b7 DM |
135 | timespan => { |
136 | description => "Select time span for included email statistics.\n\nNOTE: System and cluster performance data is always from current time (when script is run).", | |
137 | type => 'string', | |
138 | enum => ['today', 'yesterday'], | |
139 | default => 'today', | |
140 | optional => 1, | |
141 | }, | |
308c2bfc | 142 | }, |
3dfe317a DM |
143 | }, |
144 | returns => { type => 'null'}, | |
145 | code => sub { | |
146 | my ($param) = @_; | |
147 | ||
2f7031b7 DM |
148 | my $timespan = $param->{timespan} // 'today'; |
149 | my ($start, $end) = PMG::Utils::lookup_timespan($timespan); | |
3dfe317a | 150 | |
2f7031b7 | 151 | my $fqdn = PVE::Tools::get_fqdn($nodename); |
3dfe317a DM |
152 | |
153 | my $vars = { | |
154 | hostname => $nodename, | |
155 | fqdn => $fqdn, | |
156 | date => strftime("%F", localtime($end - 1)), | |
157 | }; | |
158 | ||
308c2bfc DM |
159 | my $cinfo = PMG::ClusterConfig->new(); |
160 | my $role = $cinfo->{local}->{type} // '-'; | |
161 | ||
162 | if ($role eq '-') { | |
163 | $vars->{system} = $get_system_table_data->(); | |
164 | } else { | |
165 | $vars->{cluster} = $get_cluster_table_data->(); | |
166 | if ($role eq 'master') { | |
167 | # OK | |
168 | } else { | |
169 | return undef if $param->{auto}; # silent exit - do not send report | |
170 | } | |
171 | } | |
3dfe317a | 172 | |
02251e49 DM |
173 | |
174 | my $stat = PMG::Statistic->new ($start, $end); | |
175 | my $rdb = PMG::RuleDB->new(); | |
176 | ||
177 | # update statistics | |
178 | PMG::Statistic::update_stats($rdb->{dbh}, $cinfo); | |
179 | ||
180 | my $totals = $stat->total_mail_stat($rdb); | |
02251e49 DM |
181 | |
182 | # Generate data for incoming mails | |
183 | my $data = []; | |
184 | push @$data, { text => 'Incoming Mails', value => $totals->{count_in}, percentage => $totals->{count_in_per} }; | |
7264942e DM |
185 | push @$data, { text => 'Spam Mails', value => $totals->{spamcount_in}, percentage => $totals->{spamcount_in_per} }; |
186 | push @$data, { text => 'Virus Mails', value => $totals->{viruscount_in}, percentage => $totals->{viruscount_in_per} }; | |
187 | push @$data, { text => 'SPF rejects', value => $totals->{spfcount}, percentage => $totals->{spfcount_per} }; | |
188 | push @$data, { text => 'Mail Traffic', value => sprintf ("%.3f MByte", $totals->{traffic_in}) }; | |
02251e49 DM |
189 | |
190 | $vars->{incoming} = $data, | |
191 | ||
192 | # Generate data for outgoing mails | |
193 | $data = []; | |
194 | push @$data, { text => 'Outgoing Mails', value => $totals->{count_out}, percentage => $totals->{count_out_per} }; | |
195 | push @$data, { text => 'Bounces', value => $totals->{bounces_out}, percentage => $totals->{bounces_out_per} }; | |
7264942e | 196 | push @$data, { text => 'Mail Traffic', value => sprintf ("%.3f MByte", $totals->{traffic_out}) }; |
02251e49 DM |
197 | |
198 | $vars->{outgoing} = $data, | |
199 | ||
3dfe317a DM |
200 | my $tt = PMG::Config::get_template_toolkit(); |
201 | ||
202 | my $cfg = PMG::Config->new(); | |
308c2bfc | 203 | my $email = $param->{receiver} // $cfg->get ('admin', 'email'); |
3dfe317a DM |
204 | |
205 | if (!defined($email)) { | |
308c2bfc DM |
206 | return undef if $param->{auto}; # silent exit - do not send report |
207 | die "no receiver configured\n"; | |
3dfe317a DM |
208 | } |
209 | ||
210 | my $mailfrom = "Proxmox Mail Gateway <postmaster>"; | |
211 | PMG::Utils::finalize_report($tt, 'pmgreport.tt', $vars, $mailfrom, $email, $param->{debug}); | |
212 | ||
213 | return undef; | |
214 | }}); | |
215 | ||
216 | our $cmddef = [ __PACKAGE__, 'pmgreport', [], undef ]; | |
217 | ||
218 | 1; |