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