dbe08b5bc08f9519c72a6a84bdc2f2f9884a7161
[freeside.git] / httemplate / view / Status.html
1 <& /elements/header.html, 'System Status' &>
2
3 <& /elements/init_overlib.html &>
4
5 % foreach my $section ( keys %status ) {
6 <FONT CLASS="fsinnerbox-title"><% mt($section) |h %></FONT>
7 <TABLE CLASS="fsinnerbox">
8 %   foreach my $item ( @{ $status{$section} } ) {
9       <TR>
10         <TD ALIGN="right"><% $item->{title} %></TH>
11         <TD><B><% $item->{value} %></B></TD>
12       </TR>
13 %   }
14 </TABLE>
15 <BR><BR>
16 % }
17
18 <& /elements/footer.html &>
19 <%init>
20
21 ###
22 # Basics and Daemons
23 ###
24
25 my $os;
26 -e '/usr/bin/lsb_release' and run( ['lsb_release', '-d'], '>',\$os );
27 if ( ! $@ && $os =~ /^\s*Description:\s*(.+)$/ ) {
28   $os = $1;
29 } elsif ( my $deb_version = slurp('/etc/debian_version') ) {
30   $os = "Debian $deb_version";
31 }
32
33 my $pkg_version = '';
34 -e '/usr/bin/dpkg-query'
35   and run( ['/usr/bin/dpkg-query',
36               '--showformat=${Version}', '--show', 'freeside'
37            ],
38            '>', \$pkg_version
39          );
40
41 ( my $perl_ver = $^V ) =~ s/^v//;
42
43 my $db = driver_name;
44 $db = 'PostgreSQL'    if $db =~ /^Pg/;
45 $db = 'MySQL/MariaDB' if $db =~ /^mysql/;
46
47 my $db_ver = FS::Record->scalar_sql('SELECT VERSION()');
48 if ( $db eq 'PostgreSQL' && $db_ver =~ /^\s*PostgreSQL\s+([\w\.]+)\s+on\s+/ ) {
49   $db_ver = $1;
50 }
51
52 my $db_size = 'Unknown';
53 if ( $db eq 'PostgreSQL' ) {
54   $db_size = FS::Record->scalar_sql(qq(
55                SELECT pg_size_pretty(pg_database_size('freeside'))
56              )). ' '.
57              include('/elements/popup_link.html',
58                        'action'      => 'Status-db_size_detail.html',
59                        'label'       => '(details)',
60                        'actionlabel' => 'Database size details',
61              );
62 }
63
64 tie my %status, 'Tie::IxHash',
65   'Basics' => [
66     { 'title' => 'Freeside version',
67       'value' => $FS::VERSION,
68     },
69     ( length($pkg_version)
70         ? ( { 'title' => 'Package version',
71               'value' => $pkg_version,
72             },
73           )
74         : ()
75     ),
76     { 'title' => 'Operating System',
77       'value' => $os,
78     },
79     { 'title' => 'Perl version',
80       'value' => $perl_ver,
81     },
82     { 'title' => 'Database engine',
83       'value' => $db,
84     },
85     { 'title' => 'Database version',
86       'value' => $db_ver,
87     },
88     { 'title' => 'Database size',
89       'value' => $db_size,
90     },
91   ],
92   'Required Daemons' => [
93     { 'title' => 'Queue daemon',
94       'value' => _is_running('queued') ? 'Running' : 'Not running',
95     },
96   ],
97   'Optional Daemons' => [
98     { 'title' => 'Self-service server(s)',
99       'value' => '(Not checked)', #XXX multiple pid files, per machine etc
100     },
101     { 'title' => 'Self-service XML-RPC server',
102       'value' => _is_running('selfservice-xmlrpcd') ? 'Running' : 'Not running',
103     },
104     { 'title' => 'Back office XML-RPC server',
105       'value' => _is_running('xmlrpcd') ? 'Running' : 'Not running',
106     },
107     { 'title' => 'RADIUS accounting import daemon',
108       'value' => _is_running('sqlradius-radacctd') ? 'Running' : 'Not running',
109     },
110     { 'title' => 'Prepaid daemon',
111       'value' => _is_running('prepaidd') ? 'Running' : 'Not running',
112     },
113     { 'title' => 'CDR Rewrite daemon',
114       'value' => _is_running('cdrrewrited') ? 'Running' : 'Not running',
115     },
116     { 'title' => 'CDR Prepaid daemon',
117       'value' => _is_running('cdrd') ? 'Running' : 'Not running',
118     },
119     { 'title' => 'CDR Real-time rating daemon',
120       'value' => _is_running('cdrrated') ? 'Running' : 'Not running',
121     },
122     #{ 'title' => 'Network monitoring port combiner', #?
123     #  'value' => _is_running('torrus-srvderive') ? 'Running' : 'Not running',
124     #},
125   ],
126 ;
127
128
129 ###
130 # Replication
131 ###
132
133 if ( $db eq 'PostgreSQL' ) {
134
135   my $enabled =    FS::Record->scalar_sql('SHOW wal_level')    eq 'hot_standby'
136                 && FS::Record->scalar_sql('SHOW archive_mode') eq 'on';
137
138   my $slave = 
139     FS::Record->scalar_sql('SHOW archive_command') =~ / postgres\@([\w\.\-]+):/
140       ? $1 : '';
141
142   $status{'Replication'} = [
143     { 'title' => 'Status', #?
144       'value' => $enabled ? 'Enabled' : 'Disabled',
145     },
146   ];
147
148   if ( $enabled ) {
149     push @{ $status{'Replication'} }, 
150       { 'title' => 'Slave',
151         'value' => $slave || '(Missing, or unparseable archive_command)',
152       },
153     ;
154     if ( $slave ) {
155       #how far behind is it?  will be easier once we're off 9.1
156       # http://www.keithf4.com/monitoring_streaming_slave_lag/
157       # except pg_stat_replication still doesn't fill in the columns we need as
158       # non-Pg user :/
159       #push @{ $status{'Replication'} }, 
160       #  { 'title' => 'Slave',
161       #    'value' => $slave || '(Missing, or unparseable archive_command)',
162       #  },
163       #;
164     }
165   }
166
167 } else {
168
169   $status{'Replication'} = [
170     { 'title' => 'Enabled',
171       'value' => "(Not yet checked on $db)",
172     },
173   ];
174
175 }
176
177
178 ###
179 # CDR Processing
180 ###
181
182 if ( _is_running('cdrd') ) {
183
184   my $delay = FS::Record->scalar_sql('
185     SELECT AVG(end_date-insert_date)
186       FROM queue_stat
187       GROUP BY statnum
188       ORDER BY statnum DESC
189       LIMIT 100
190   ');
191   if ( $delay ) {
192     my $h = int($delay/3600);
193     my $m = int( ($delay%3600) / 60 );
194     my $s = $delay%60;
195
196     $delay = ( $h     ? $h. 'h' : '' ).
197              ( $h||$m ? $m. 'm' : '').
198                         $s. 's';
199
200   }
201
202   my $pr_delay = FS::Record->scalar_sql('
203     SELECT AVG(end_date-start_date)
204       FROM queue_stat
205       GROUP BY statnum
206       ORDER BY statnum DESC
207       LIMIT 100
208   ');
209   if ( $pr_delay ) {
210     my $h = int($delay/3600);
211     my $m = int( ($delay%3600) / 60 );
212     my $s = $delay%60;
213
214     $pr_delay = ( $h     ? $h. 'h' : '' ).
215                 ( $h||$m ? $m. 'm' : '').
216                            $s. 's';
217
218   }
219
220   my $dayago = time2str('%Y-%m-%d %X', time - 86400);
221   my $cdrs = FS::Record->scalar_sql(qq{
222     SELECT COUNT(*) FROM cdr
223       WHERE ( freesidestatus IS NULL OR freesidestatus = '' )
224         AND calldate > '$dayago'
225   });
226
227   $status{'CDR Processing'} = [
228     { 'title' => 'Current processing delay',
229       'value' => $delay,
230     },
231     { 'title' => 'Average billing time',
232       'value' => $pr_delay,
233     },
234     { 'title' => 'Unprocessed CDRs (last 24 hours)',
235       'value' => $cdrs,
236     },
237   ];
238
239 }
240
241
242 ###
243 # PCI Compliance
244 ###
245
246 my($store, $tokenize) = (0,0);
247 foreach my $agent (
248   qsearch({
249     'table'     => 'agent',
250     'hashref'   => { 'disabled' => '', },
251     'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql,
252   })
253 ) {
254   my $gateway = $agent->payment_gateway('method'=>'VISA card', 'nofatal'=>1, );
255   next unless $gateway
256            && $gateway->gateway_namespace eq 'Business::OnlinePayment';
257   eval "use Business::OnlinePayment";
258   die $@ if $@; #die?
259   my $bop = new Business::OnlinePayment( $gateway->gateway_module,
260                                          $gateway->gatewaynum
261                                            ? $gateway->options
262                                            : @{ $gateway->get('options') }
263                                        );
264   my %actions = $bop->info('supported_actions');
265   if ( $actions{'CC'} && grep /^Tokenize$/, @{$actions{'CC'}} ) {
266     $tokenize++;
267   } else {
268     $store++;
269   }
270   
271 }
272
273 if ( $tokenize && ! $store ) {
274
275   $status{'PCI Compliance'} = [
276     { 'title' => 'Tokenization',
277       'value' => 'Enabled',
278     },
279     { 'title' => 'SAQ type',
280       'value' => 'A / A-EP',
281     },
282   ];
283
284 } elsif ( $store ) {
285
286   my $conf = new FS::Conf; #wow, didn't need this before?
287
288   $status{'PCI Compliance'} = [
289     { 'title' => 'Tokenization',
290       'value' => $tokenize ? 'Partialy enabled (some agents)' : 'Disabled'
291     },
292     { 'title' => 'Encryption',
293       'value' =>
294         ( $conf->exists('encryption') && $conf->config('encryptionpublickey')
295             ? 'Enabled' : 'Disabled'
296         ),
297     },
298     { 'title' => 'SAQ type',
299       'value' => 'D (enable tokenization for A / A-EP)',
300     },
301   ];
302
303 }
304
305 ###
306 # Subroutines
307 ###
308
309 sub _is_running {
310   my $thing = shift;
311
312   my $pid_path = '/var/run'; #XXX hardcoded path
313
314   my $pidfile =
315     -e "$pid_path/freeside/$thing.pid" ? "$pid_path/freeside/$thing.pid" :
316     -e "$pid_path/freeside-$thing.pid" ? "$pid_path/freeside-$thing.pid" :
317    return 0;
318
319   -e $pidfile and kill 0, slurp($pidfile)
320 }
321
322 </%init>