& /elements/header.html, 'System Status' &>
% foreach my $section ( keys %status ) {
<% mt($section) |h %>
% foreach my $item ( @{ $status{$section} } ) {
<% $item->{title} %>
| <% $item->{value} %> |
% }
% }
<& /elements/footer.html &>
<%init>
###
# Basics and Daemons
###
my $os;
-e '/usr/bin/lsb_release' and run( ['lsb_release', '-d'], '>',\$os );
if ( ! $@ && $os =~ /^\s*Description:\s*(.+)$/ ) {
$os = $1;
} elsif ( my $deb_version = slurp('/etc/debian_version') ) {
$os = "Debian $deb_version";
}
( my $perl_ver = $^V ) =~ s/^v//;
my $db = driver_name;
$db = 'PostgreSQL' if $db =~ /^Pg/;
$db = 'MySQL/MariaDB' if $db =~ /^mysql/;
my $db_ver = FS::Record->scalar_sql('SELECT VERSION()');
if ( $db eq 'PostgreSQL' && $db_ver =~ /^\s*PostgreSQL\s+([\w\.]+)\s+on\s+/ ) {
$db_ver = $1;
}
my $db_size = 'Unknown';
if ( $db eq 'PostgreSQL' ) {
$db_size = FS::Record->scalar_sql(qq(
SELECT pg_size_pretty(pg_database_size('freeside'))
));
}
tie my %status, 'Tie::IxHash',
'Basics' => [
{ 'title' => 'Freeside version',
'value' => $FS::VERSION,
},
{ 'title' => 'Operating System',
'value' => $os,
},
{ 'title' => 'Perl version',
'value' => $perl_ver,
},
{ 'title' => 'Database engine',
'value' => $db,
},
{ 'title' => 'Database version',
'value' => $db_ver,
},
{ 'title' => 'Database size',
'value' => $db_size,
},
],
'Required Daemons' => [
{ 'title' => 'Queue daemon',
'value' => _is_running('queued') ? 'Running' : 'Not running',
},
],
'Optional Daemons' => [
{ 'title' => 'Self-service server(s)',
'value' => '(Not checked)', #XXX multiple pid files, per machine etc
},
{ 'title' => 'Self-service XML-RPC server',
'value' => _is_running('selfservice-xmlrpcd') ? 'Running' : 'Not running',
},
{ 'title' => 'Back office XML-RPC server',
'value' => _is_running('xmlrpcd') ? 'Running' : 'Not running',
},
{ 'title' => 'RADIUS accounting import daemon',
'value' => _is_running('sqlradius-radacctd') ? 'Running' : 'Not running',
},
{ 'title' => 'Prepaid daemon',
'value' => _is_running('prepaidd') ? 'Running' : 'Not running',
},
{ 'title' => 'CDR Rewrite daemon',
'value' => _is_running('cdrrewrited') ? 'Running' : 'Not running',
},
{ 'title' => 'CDR Prepaid daemon',
'value' => _is_running('cdrd') ? 'Running' : 'Not running',
},
{ 'title' => 'CDR Real-time rating daemon',
'value' => _is_running('cdrrated') ? 'Running' : 'Not running',
},
#{ 'title' => 'Network monitoring port combiner', #?
# 'value' => _is_running('torrus-srvderive') ? 'Running' : 'Not running',
#},
],
;
###
# Replication
###
if ( $db eq 'PostgreSQL' ) {
my $enabled = FS::Record->scalar_sql('SHOW wal_level') eq 'hot_standby'
&& FS::Record->scalar_sql('SHOW archive_mode') eq 'on';
my $slave =
FS::Record->scalar_sql('SHOW archive_command') =~ / postgres\@([\w\.\-]+): /
? $1 : '';
$status{'Replication'} = [
{ 'title' => 'Status', #?
'value' => $enabled ? 'Enabled' : 'Disabled',
},
];
if ( $enabled ) {
push @{ $status{'Replication'} },
{ 'title' => 'Slave',
'value' => $slave || '(Missing, or unparseable archive_command)',
},
;
if ( $slave ) {
#how far behind is it? will be easier once we're off 9.1
# http://www.keithf4.com/monitoring_streaming_slave_lag/
# except pg_stat_replication still doesn't fill in the columns we need as
# non-Pg user :/
push @{ $status{'Replication'} },
{ 'title' => 'Slave',
'value' => $slave || '(Missing, or unparseable archive_command)',
},
;
}
}
} else {
$status{'Replication'} = [
{ 'title' => 'Enabled',
'value' => "(Not yet checked on $db)",
},
];
}
###
# CDR Processing
###
if ( _is_running('cdrd') ) {
my $delay = FS::Record->scalar_sql('
SELECT AVG(end_date-insert_date)
FROM queue_stat
GROUP BY statnum
ORDER BY statnum DESC
LIMIT 100
');
if ( $delay ) {
my $h = int($delay/3600);
my $m = int( ($delay%3600) / 60 );
my $s = $delay%60;
$delay = ( $h ? $h. 'h' : '' ).
( $h||$m ? $m. 'm' : '').
$s. 's';
}
my $pr_delay = FS::Record->scalar_sql('
SELECT AVG(end_date-start_date)
FROM queue_stat
GROUP BY statnum
ORDER BY statnum DESC
LIMIT 100
');
if ( $pr_delay ) {
my $h = int($delay/3600);
my $m = int( ($delay%3600) / 60 );
my $s = $delay%60;
$pr_delay = ( $h ? $h. 'h' : '' ).
( $h||$m ? $m. 'm' : '').
$s. 's';
}
my $dayago = time2str('%Y-%m-%d %X', time - 86400);
my $cdrs = FS::Record->scalar_sql(qq{
SELECT COUNT(*) FROM cdr
WHERE ( freesidestatus IS NULL OR freesidestatus = '' )
AND calldate > '$dayago'
});
$status{'CDR Processing'} = [
{ 'title' => 'Current processing delay',
'value' => $delay,
},
{ 'title' => 'Average billing time',
'value' => $pr_delay,
},
{ 'title' => 'Unprocessed CDRs (last 24 hours)',
'value' => $cdrs,
},
];
}
###
# PCI Compliance
###
my($store, $tokenize) = (0,0);
foreach my $agent (
qsearch({
'table' => 'agent',
'hashref' => { 'disabled' => '', },
'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql,
})
) {
my $gateway = $agent->payment_gateway('method'=>'VISA card', 'nofatal'=>1, );
next unless $gateway
&& $gateway->gateway_namespace eq 'Business::OnlinePayment';
eval "use Business::OnlinePayment";
die $@ if $@; #die?
my $bop = new Business::OnlinePayment( $gateway->gateway_module,
$gateway->gatewaynum
? $gateway->options
: @{ $gateway->get('options') }
);
my %actions = $bop->info('supported_actions');
if ( $actions{'CC'} && grep /^Tokenize$/, @{$actions{'CC'}} ) {
$tokenize++;
} else {
$store++;
}
}
if ( $tokenize && ! $store ) {
$status{'PCI Compliance'} = [
{ 'title' => 'Tokenization',
'value' => 'Enabled',
},
{ 'title' => 'SAQ type',
'value' => 'A / A-EP',
},
];
} elsif ( $store ) {
my $conf = new FS::Conf; #wow, didn't need this before?
$status{'PCI Compliance'} = [
{ 'title' => 'Tokenization',
'value' => $tokenize ? 'Partialy enabled (some agents)' : 'Disabled'
},
{ 'title' => 'Encryption',
'value' =>
( $conf->exists('encryption') && $conf->config('encryptionpublickey')
? 'Enabled' : 'Disabled'
),
},
{ 'title' => 'SAQ type',
'value' => 'D (enable tokenization for A / A-EP)',
},
];
}
###
# Subroutines
###
sub _is_running {
my $thing = shift;
my $pid_path = '/var/run'; #XXX hardcoded path
my $pidfile =
-e "$pid_path/freeside/$thing.pid" ? "$pid_path/freeside/$thing.pid" :
-e "$pid_path/freeside-$thing.pid" ? "$pid_path/freeside-$thing.pid" :
return 0;
-e $pidfile and kill 0, slurp($pidfile)
}
%init>