<& /elements/header.html, 'System Status' &> <& /elements/init_overlib.html &> % 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 $pkg_version = ''; -e '/usr/bin/dpkg-query' and run( ['/usr/bin/dpkg-query', '--showformat=${Version}', '--show', 'freeside' ], '>', \$pkg_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+\([\w\s\.\+\-\:\~]+\))?)\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')) )). ' '. include('/elements/popup_link.html', 'action' => 'Status-db_size_detail.html', 'label' => '(details)', 'actionlabel' => 'Database size details', ); } tie my %status, 'Tie::IxHash', 'Basics' => [ { 'title' => 'Freeside version', 'value' => $FS::VERSION, }, ( length($pkg_version) ? ( { 'title' => 'Package version', 'value' => $pkg_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) }