1721 lines
53 KiB
Perl
1721 lines
53 KiB
Perl
#!/usr/bin/perl
|
|
#
|
|
# AST_update_AMI2.pl version 2.14
|
|
#
|
|
# This script uses the Asterisk Manager interface to update the live_channels
|
|
# tables and verify the parked_channels table in the asterisk MySQL database
|
|
#
|
|
# Copyright (C) 2018 Matt Florell <vicidial@gmail.com> LICENSE: AGPLv2
|
|
#
|
|
# CHANGES
|
|
# 170915-2110 - Initial version for Asterisk 13, based upon AST_update.pl
|
|
# 171002-1111 - Fixed timeout erase channels issue, added more debug output
|
|
# 171228-1832 - Added more debug logging
|
|
# 180511-1146 - Changed to use server-specific cid_channels_recent table
|
|
# 181003-1728 - Fix for RINGAGENT calls
|
|
# 190102-1509 - More fixes for RINGAGENT Calls
|
|
#
|
|
|
|
# constants
|
|
$DB=0; # Debug flag, set to 0 for no debug messages, lots of output
|
|
$DBX=0;
|
|
$run_check=1; # concurrency check
|
|
|
|
# loop time in seconds
|
|
$loop_time = 0.4;
|
|
|
|
# how often settings should be reloaded from the DB in seconds
|
|
$settings_reload_interval = 10;
|
|
|
|
# how often the server stats are updated
|
|
$server_stats_update_interval = 30;
|
|
|
|
# how often performance logging is triggered
|
|
$performance_logging_interval = 5;
|
|
|
|
### begin parsing run-time options ###
|
|
if (length($ARGV[0])>1)
|
|
{
|
|
$i=0;
|
|
while ($#ARGV >= $i)
|
|
{
|
|
$args = "$args $ARGV[$i]";
|
|
$i++;
|
|
}
|
|
|
|
if ($args =~ /--help/i)
|
|
{
|
|
print "allowed run time options:\n";
|
|
print " [--test] = test\n";
|
|
print " [--debug] = verbose debug messages\n";
|
|
print " [--debugX] = Extra-verbose debug messages\n";
|
|
print " [--help] = this screen\n";
|
|
print "\n";
|
|
exit;
|
|
}
|
|
else
|
|
{
|
|
if ($args =~ /--debug/i)
|
|
{
|
|
$DB=1; # Debug flag
|
|
print "\n----- DEBUGGING ENABLED -----\n\n";
|
|
}
|
|
if ($args =~ /--debugX/i)
|
|
{
|
|
$DBX=1;
|
|
print "\n----- SUPER-DUPER DEBUGGING -----\n\n";
|
|
}
|
|
if ($args =~ /--test/i)
|
|
{
|
|
$TEST=1;
|
|
$T=1;
|
|
}
|
|
}
|
|
}
|
|
### end parsing run-time options ###
|
|
|
|
# default path to astguiclient configuration file:
|
|
$PATHconf = '/etc/astguiclient.conf';
|
|
|
|
open(conf, "$PATHconf") || die "can't open $PATHconf: $!\n";
|
|
@conf = <conf>;
|
|
close(conf);
|
|
$i=0;
|
|
foreach(@conf)
|
|
{
|
|
$line = $conf[$i];
|
|
$line =~ s/ |>|\n|\r|\t|\#.*|;.*//gi;
|
|
if ($line =~ /^PATHhome/) {$PATHhome = $line; $PATHhome =~ s/.*=//gi;}
|
|
if ($line =~ /^PATHlogs/) {$PATHlogs = $line; $PATHlogs =~ s/.*=//gi;}
|
|
if ($line =~ /^PATHagi/) {$PATHagi = $line; $PATHagi =~ s/.*=//gi;}
|
|
if ($line =~ /^PATHweb/) {$PATHweb = $line; $PATHweb =~ s/.*=//gi;}
|
|
if ($line =~ /^PATHsounds/) {$PATHsounds = $line; $PATHsounds =~ s/.*=//gi;}
|
|
if ($line =~ /^PATHmonitor/) {$PATHmonitor = $line; $PATHmonitor =~ s/.*=//gi;}
|
|
if ($line =~ /^VARserver_ip/) {$VARserver_ip = $line; $VARserver_ip =~ s/.*=//gi;}
|
|
if ($line =~ /^VARDB_server/) {$VARDB_server = $line; $VARDB_server =~ s/.*=//gi;}
|
|
if ($line =~ /^VARDB_database/) {$VARDB_database = $line; $VARDB_database =~ s/.*=//gi;}
|
|
if ($line =~ /^VARDB_user/) {$VARDB_user = $line; $VARDB_user =~ s/.*=//gi;}
|
|
if ($line =~ /^VARDB_pass/) {$VARDB_pass = $line; $VARDB_pass =~ s/.*=//gi;}
|
|
if ($line =~ /^VARDB_custom_user/) {$VARDB_custom_user = $line; $VARDB_custom_user =~ s/.*=//gi;}
|
|
if ($line =~ /^VARDB_custom_pass/) {$VARDB_custom_pass = $line; $VARDB_custom_pass =~ s/.*=//gi;}
|
|
if ($line =~ /^VARDB_port/) {$VARDB_port = $line; $VARDB_port =~ s/.*=//gi;}
|
|
$i++;
|
|
}
|
|
|
|
# Customized Variables
|
|
$server_ip = $VARserver_ip; # Asterisk server IP
|
|
|
|
|
|
### find df binary (partition usage)
|
|
$dfbin = '';
|
|
if ( -e ('/bin/df')) {$dfbin = '/bin/df';}
|
|
else
|
|
{
|
|
if ( -e ('/usr/bin/df')) {$dfbin = '/usr/bin/df';}
|
|
else
|
|
{
|
|
if ( -e ('/usr/local/bin/df')) {$dfbin = '/usr/local/bin/df';}
|
|
else
|
|
{
|
|
print "Can't find df binary! Exiting...\n";
|
|
exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (!$VARDB_port) {$VARDB_port='3306';}
|
|
|
|
&get_time_now;
|
|
|
|
#use lib './lib', '../lib';
|
|
use Time::HiRes ('gettimeofday','usleep','sleep'); # necessary to have perl sleep command of less than one second
|
|
use DBI;
|
|
use Net::Telnet ();
|
|
use Switch;
|
|
use POSIX;
|
|
use Scalar::Util qw(looks_like_number);
|
|
use Term::ANSIColor qw(:constants);
|
|
|
|
|
|
$module = 'String::Escape qw( backslash unbackslash )';
|
|
$bs_loaded=0;
|
|
if (try_load($module))
|
|
{
|
|
$bs_loaded=1;
|
|
}
|
|
|
|
|
|
$dbhA = DBI->connect("DBI:mysql:$VARDB_database:$VARDB_server:$VARDB_port", "$VARDB_user", "$VARDB_pass")
|
|
or die "Couldn't connect to database: " . DBI->errstr;
|
|
|
|
### Grab Server values from the database
|
|
$stmtA = "SELECT telnet_host,telnet_port,ASTmgrUSERNAME,ASTmgrSECRET,ASTmgrUSERNAMEupdate,ASTmgrUSERNAMElisten,ASTmgrUSERNAMEsend,max_vicidial_trunks,answer_transfer_agent,local_gmt,ext_context,vd_server_logs,asterisk_version FROM servers where server_ip = '$server_ip';";
|
|
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
|
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
|
$sthArows=$sthA->rows;
|
|
if ($sthArows > 0)
|
|
{
|
|
@aryA = $sthA->fetchrow_array;
|
|
$DBtelnet_host = $aryA[0];
|
|
$DBtelnet_port = $aryA[1];
|
|
$DBASTmgrUSERNAME = $aryA[2];
|
|
$DBASTmgrSECRET = $aryA[3];
|
|
$DBASTmgrUSERNAMEupdate = $aryA[4];
|
|
$DBASTmgrUSERNAMElisten = $aryA[5];
|
|
$DBASTmgrUSERNAMEsend = $aryA[6];
|
|
$DBmax_vicidial_trunks = $aryA[7];
|
|
$DBanswer_transfer_agent= $aryA[8];
|
|
$DBSERVER_GMT = $aryA[9];
|
|
$DBext_context = $aryA[10];
|
|
$DBvd_server_logs = $aryA[11];
|
|
$asterisk_version = $aryA[12];
|
|
if ($DBtelnet_host) {$telnet_host = $DBtelnet_host;}
|
|
if ($DBtelnet_port) {$telnet_port = $DBtelnet_port;}
|
|
if ($DBASTmgrUSERNAME) {$ASTmgrUSERNAME = $DBASTmgrUSERNAME;}
|
|
if ($DBASTmgrSECRET) {$ASTmgrSECRET = $DBASTmgrSECRET;}
|
|
if ($DBASTmgrUSERNAMEupdate) {$ASTmgrUSERNAMEupdate = $DBASTmgrUSERNAMEupdate;}
|
|
if ($DBASTmgrUSERNAMEupdate) {$ASTmgrUSERNAMEupdate = $DBASTmgrUSERNAMEupdate;}
|
|
if ($DBASTmgrUSERNAMEsend) {$ASTmgrUSERNAMEsend = $DBASTmgrUSERNAMEsend;}
|
|
if ($DBmax_vicidial_trunks) {$max_vicidial_trunks = $DBmax_vicidial_trunks;}
|
|
if ($DBanswer_transfer_agent) {$answer_transfer_agent = $DBanswer_transfer_agent;}
|
|
if ($DBSERVER_GMT) {$SERVER_GMT = $DBSERVER_GMT;}
|
|
if ($DBext_context) {$ext_context = $DBext_context;}
|
|
if ($DBvd_server_logs =~ /Y/) {$SYSLOG = '1';}
|
|
else {$SYSLOG = '0';}
|
|
}
|
|
|
|
if (!$telnet_port) {$telnet_port = '5038';}
|
|
|
|
|
|
##### Check for a server_updater record, and if not present, insert one
|
|
$SUrec=0;
|
|
$stmtA = "SELECT count(*) FROM server_updater where server_ip='$server_ip';";
|
|
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
|
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
|
@aryA = $sthA->fetchrow_array;
|
|
$SUrec = $aryA[0];
|
|
if($DB){print STDERR "\n|$SUrec|$stmtA|\n";}
|
|
|
|
if ($SUrec < 1)
|
|
{
|
|
&get_time_now;
|
|
|
|
$stmtU = "INSERT INTO server_updater set server_ip='$server_ip', last_update=NOW();";
|
|
if($DB){print STDERR "\n$stmtU\n";}
|
|
$affected_rows = $dbhA->do($stmtU);
|
|
}
|
|
|
|
$event_string='LOGGED INTO MYSQL SERVER ON 1 CONNECTION|';
|
|
event_logger($SYSLOG,$event_string);
|
|
|
|
|
|
##### BEGIN Check for a cid_channels_recent_IPXXXXX... table, and if not present, create one
|
|
$cid_channels_recent = 'cid_channels_recent';
|
|
$PADserver_ip = $server_ip;
|
|
$PADserver_ip =~ s/(\d+)(\.|$)/sprintf "%3.3d$2",$1/eg;
|
|
$PADserver_ip =~ s/\.//eg;
|
|
$CCRrec=0; $affected_rowsCCR=0;
|
|
$stmtA = "SHOW TABLES LIKE \"cid_channels_recent_$PADserver_ip\";";
|
|
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
|
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
|
$CCRrec=$sthA->rows;
|
|
if($DB){print STDERR "\n|$CCRrec|$stmtA|\n";}
|
|
|
|
if ($CCRrec > 0)
|
|
{$cid_channels_recent = "cid_channels_recent_$PADserver_ip";}
|
|
else
|
|
{
|
|
$dbhB = DBI->connect("DBI:mysql:$VARDB_database:$VARDB_server:$VARDB_port", "$VARDB_custom_user", "$VARDB_custom_pass")
|
|
or warn "Couldn't connect to database: " . DBI->errstr;
|
|
|
|
$stmtB = "CREATE TABLE cid_channels_recent_$PADserver_ip (caller_id_name VARCHAR(30) NOT NULL, connected_line_name VARCHAR(30) NOT NULL, call_date DATETIME, channel VARCHAR(100) DEFAULT '', dest_channel VARCHAR(100) DEFAULT '', linkedid VARCHAR(20) DEFAULT '', dest_uniqueid VARCHAR(20) DEFAULT '', uniqueid VARCHAR(20) DEFAULT '', index(call_date)) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;";
|
|
if($DB){print STDERR "\n$stmtB\n";}
|
|
eval { $affected_rowsCCR = $dbhB->do($stmtB) };
|
|
print "Query failed: $@\n" if $@;
|
|
|
|
eval { $dbhB->disconnect() };
|
|
print "Disconnect failed: $@\n" if $@;
|
|
|
|
$stmtA = "SHOW TABLES LIKE \"cid_channels_recent_$PADserver_ip\";";
|
|
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
|
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
|
$CCRrec=$sthA->rows;
|
|
if($DB){print STDERR "\n|$CCRrec|$stmtA|\n";}
|
|
|
|
if ($CCRrec > 0)
|
|
{$cid_channels_recent = "cid_channels_recent_$PADserver_ip";}
|
|
}
|
|
print STDERR "$CCRrec|$cid_channels_recent|$stmtA\n";
|
|
|
|
$event_string='TABLE CHECK cid_channels_recent_$PADserver_ip complete|$CCRrec|$affected_rowsCCR|';
|
|
event_logger($SYSLOG,$event_string);
|
|
##### END Check for a cid_channels_recent_IPXXXXX... table, and if not present, create one
|
|
|
|
|
|
### concurrency check (SCREEN uses script path, so check for more than 2 entries)
|
|
if ($run_check > 0)
|
|
{
|
|
my $grepout = `/bin/ps ax | grep $0 | grep -v grep | grep -v '/bin/sh'`;
|
|
my $grepnum=0;
|
|
$grepnum++ while ($grepout =~ m/\n/g);
|
|
if ($grepnum > 2)
|
|
{
|
|
if ($DB) {print "I am not alone! Another $0 is running! Exiting...\n";}
|
|
$event_string = "I am not alone! Another $0 is running! Exiting...";
|
|
&event_logger($SYSLOG,$event_string);
|
|
exit;
|
|
}
|
|
}
|
|
|
|
|
|
$event_string="STARTING NEW MANAGER TELNET CONNECTION||ATTEMPT|ONE DAY INTERVAL:$one_day_interval|";
|
|
event_logger($SYSLOG,$event_string);
|
|
|
|
$max_buffer = 4*1024*1024; # 4 meg buffer
|
|
|
|
### connect to asterisk manager through telnet
|
|
$tn = new Net::Telnet (
|
|
Port => $telnet_port,
|
|
Prompt => '/\r\n/',
|
|
Output_record_separator => "\n\n",
|
|
Max_buffer_length => $max_buffer,
|
|
Telnetmode => 0,
|
|
);
|
|
|
|
$UPtelnetlog = "$PATHlogs/update_telnet_log.txt"; # uncomment for telnet log
|
|
#$fh = $tn->dump_log("$UPtelnetlog"); # uncomment for telnet log
|
|
|
|
if (length($ASTmgrUSERNAMEupdate) > 3) {$telnet_login = $ASTmgrUSERNAMEupdate;}
|
|
else {$telnet_login = $ASTmgrUSERNAME;}
|
|
$tn->open("$telnet_host");
|
|
$tn->waitfor('/Asterisk Call Manager\//');
|
|
|
|
# get the AMI version number
|
|
$ami_version = $tn->getline(Errmode => Return, Timeout => 1,);
|
|
$ami_version =~ s/\n//gi;
|
|
print "----- AMI Version $ami_version -----\n";
|
|
|
|
# Login
|
|
$tn->print("Action: Login\nUsername: $telnet_login\nSecret: $ASTmgrSECRET");
|
|
$tn->waitfor('/Authentication accepted/'); # waitfor auth accepted
|
|
|
|
$tn->buffer_empty;
|
|
|
|
$event_string="STARTING NEW MANAGER TELNET CONNECTION|$telnet_login|CONFIRMED CONNECTION|AMI Version $ami_version|ONE DAY INTERVAL:$one_day_interval|";
|
|
event_logger($SYSLOG,$event_string);
|
|
|
|
%ast_ver_str = parse_asterisk_version($asterisk_version);
|
|
if (( $ast_ver_str{major} = 1 ) && ($ast_ver_str{minor} < 13))
|
|
{
|
|
print "Asterisk version too low for this script. Exiting.\n\n\n";
|
|
$event_string = "Asterisk version too low for this script. Exiting.";
|
|
&event_logger($SYSLOG,$event_string);
|
|
exit;
|
|
}
|
|
else
|
|
{
|
|
### BEGIN manager event handling for asterisk version >= 13
|
|
$endless_loop = 1;
|
|
$loop_count = 0;
|
|
|
|
# get the number of microseconds the loop is supposed to take
|
|
$loop_time_usec = $loop_time * 1000000;
|
|
$loop_time_usec = ceil($loop_time_usec); # take care of any floating point math
|
|
|
|
# total of the number of bad channel grabs from Asterisk
|
|
$total_bad_grabs = 0;
|
|
|
|
# the last time our settings were loaded from the DB
|
|
$last_config_reload = 0;
|
|
|
|
# the last time the server stats were updated
|
|
$last_stats_update = 0;
|
|
|
|
# the last time the performance data was logged
|
|
$last_perf_log = 0;
|
|
|
|
# the various channel counts from the last loop
|
|
$counts->{'psuedo'} = 0;
|
|
$counts->{'total'} = 0;
|
|
$counts->{'trunks'} = 0;
|
|
$counts->{'clients'} = 0;
|
|
$counts->{'sip'} = 0;
|
|
$counts->{'iax'} = 0;
|
|
$counts->{'dahdi'} = 0;
|
|
$counts->{'local'} = 0;
|
|
$counts->{'other'} = 0;
|
|
|
|
%parked_channels_hash = {};
|
|
$parked_channels = \%parked_channels_hash;
|
|
|
|
while($endless_loop)
|
|
{
|
|
# increment total loop counter
|
|
$loop_count++;
|
|
|
|
# make a copy of our counts
|
|
%old_counts_hash = %{ $counts };
|
|
$old_counts = \%old_counts_hash;
|
|
|
|
# get the current time
|
|
( $now_sec, $now_micro_sec ) = gettimeofday();
|
|
|
|
# figure out how many micro seconds since epoch
|
|
$now_micro_epoch = $now_sec * 1000000;
|
|
$now_micro_epoch = $now_micro_epoch + $now_micro_sec;
|
|
|
|
$begin_micro_epoch = $now_micro_epoch;
|
|
|
|
# create a new action id
|
|
$action_id = "$now_sec.$now_micro_sec";
|
|
|
|
$modechange = $tn->errmode('return');
|
|
|
|
# ask the AMI for the channels
|
|
$action_string = "Action: CoreShowChannels\nActionID: $action_id";
|
|
$tn->print($action_string);
|
|
|
|
# wait till we get the response
|
|
$tn->waitfor('/Message: Channels will follow\n\n/');
|
|
$msg = $tn->errmsg;
|
|
if ( $msg ne '' )
|
|
{
|
|
$event_string = "WAITFOR ERRMSG: |$msg|$now_date|" . length($read_input_buf) . "|$endless_loop|$loop_count|Command: $action_string|";
|
|
&event_logger($SYSLOG,$event_string);
|
|
print $event_string."\n";
|
|
}
|
|
|
|
# initialize the channal array
|
|
@chan_array = ();
|
|
|
|
# prepare to loop
|
|
$get_channels = 1;
|
|
|
|
# total number of channels pulled
|
|
$total_channels = 0;
|
|
|
|
# whether this channel pull was bad
|
|
$bad_grab = 0;
|
|
|
|
&get_time_now;
|
|
if ($DB) { print "\n\n$now_date\n|Channel List:\n"; }
|
|
|
|
# Loop to get all of the channels
|
|
$event_ref = {};
|
|
|
|
$match_string = '/Event: CoreShowChannelsComplete\nActionID: ' . $action_id . '\nEventList: Complete\nListItems: \d+/';
|
|
|
|
# get an entire record
|
|
( $read_input_buf, $match ) = $tn->waitfor(Errmode => Return, Timeout => 1, Match => "$match_string" );
|
|
|
|
chomp( $read_input_buf );
|
|
|
|
if (($DBX) && ($bs_loaded) && (length($read_input_buf) > 0)) { print "|read|" . backslash( $read_input_buf ) . "|\n"; }
|
|
|
|
if (($DBX) && ($bs_loaded) && (length($read_input_buf) > 0)) { print "|match|" . backslash( $match ) . "|\n"; }
|
|
|
|
|
|
( $junk, $list_items) = split( /ListItems: /, $match );
|
|
|
|
if ($DBX) { print "|total_channels|$list_items\n"; }
|
|
|
|
# check if there were any errors
|
|
$msg='';
|
|
$msg = $tn->errmsg;
|
|
if ( ( $msg ne '' ) && ( $msg !~ /read timed-out/i ) )
|
|
{
|
|
if ($msg =~ /filehandle isn\'t open/i)
|
|
{
|
|
# we have lost connection
|
|
$endless_loop=0;
|
|
$one_day_interval=0;
|
|
print "ERRMSG: |$msg|$now_date|" . length($read_input_buf) . "|$endless_loop|$loop_count|\n";
|
|
print "\nAsterisk server shutting down, PROCESS KILLED... EXITING\n\n";
|
|
$event_string="Asterisk server shutting down, PROCESS KILLED... EXITING|ONE DAY INTERVAL:$one_day_interval|$msg|";
|
|
event_logger($SYSLOG,$event_string);
|
|
}
|
|
else
|
|
{
|
|
# something happened
|
|
print "ERRMSG: |$msg|$now_date|" . length($read_input_buf) . "|$endless_loop|$loop_count|Command: $action_string|Match String: $match_string|\n";
|
|
$bad_grab = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
@records = split( /\n\n/, $read_input_buf );
|
|
foreach my $record ( @records )
|
|
{
|
|
# Loop to get all of the channels
|
|
$event_ref = {};
|
|
|
|
# break the record into lines
|
|
@lines = split( /\n/, $record );
|
|
foreach my $line ( @lines)
|
|
{
|
|
# add the line to the hash
|
|
($key,$value) = split( /: /, $line );
|
|
if ($key ne "")
|
|
{
|
|
$value =~ s/\n//gi; # remove new lines
|
|
$value =~ s/^ +//gi; # remove leading white space
|
|
$value =~ s/ +$//gi; # remove trailing white space
|
|
|
|
# change certain strings to conform with Asterisk 1.0 behavior
|
|
$value =~ s/Congestion\s+\(Empty\)/ SIP\/CONGEST/gi;
|
|
$value =~ s/\(Outgoing Line\)|\(None\)/SIP\/ring/gi;
|
|
$value =~ s/\(Empty\)/SIP\/internal/gi;
|
|
$event_ref->{"$key"} = $value;
|
|
}
|
|
}
|
|
|
|
$hash_size = keys(%$event_ref);
|
|
|
|
if ( ($DB) && ( $hash_size > 2 ) )
|
|
{
|
|
if ( $event_ref->{'Event'} eq "CoreShowChannel" )
|
|
{
|
|
if ( $total_channels == 0 )
|
|
{
|
|
print "|Channel|ChannelState|ChannelStateDesc|Exten|Priority|Context|CallerIDName|CallerIDNum|ConnectedLineName|ConnectedLineNum|Uniqueid|Linkedid|Application|ApplicationData|BridgeId|AccountCode|Language|Duration|\n";
|
|
}
|
|
|
|
print "|$event_ref->{'Channel'}";
|
|
print "|$event_ref->{'ChannelState'}";
|
|
print "|$event_ref->{'ChannelStateDesc'}";
|
|
print "|$event_ref->{'Exten'}";
|
|
print "|$event_ref->{'Priority'}";
|
|
print "|$event_ref->{'Context'}";
|
|
print "|$event_ref->{'CallerIDName'}";
|
|
print "|$event_ref->{'CallerIDNum'}";
|
|
print "|$event_ref->{'ConnectedLineName'}";
|
|
print "|$event_ref->{'ConnectedLineNum'}";
|
|
print "|$event_ref->{'Uniqueid'}";
|
|
print "|$event_ref->{'Linkedid'}";
|
|
print "|$event_ref->{'Application'}";
|
|
print "|$event_ref->{'ApplicationData'}";
|
|
print "|$event_ref->{'BridgeId'}";
|
|
print "|$event_ref->{'AccountCode'}";
|
|
print "|$event_ref->{'Language'}";
|
|
print "|$event_ref->{'Duration'}|";
|
|
print "\n";
|
|
}
|
|
}
|
|
|
|
$event_ref->{'AMIVersion'} = $ami_version;
|
|
$event_ref->{'ServerIP'} = $server_ip;
|
|
|
|
|
|
$retcode = 1;
|
|
# make sure this is an event not a response
|
|
if (exists($event_ref->{"Event"}))
|
|
{
|
|
if ( $event_ref->{"Event"} eq "CoreShowChannel" )
|
|
{
|
|
$total_channels++;
|
|
# We got a channel
|
|
if ( $event_ref->{"ActionID"} eq $action_id )
|
|
{
|
|
push( @chan_array, $event_ref );
|
|
}
|
|
else
|
|
{
|
|
if ($DB) { print STDERR "We got the wrong Action ID!!!!\n"; }
|
|
}
|
|
}
|
|
else
|
|
{
|
|
# We got something else???
|
|
}
|
|
}
|
|
elsif ( exists($event_ref->{"Response"}) )
|
|
{
|
|
# we got the response. Channels should follow.
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( $total_channels != $list_items )
|
|
{
|
|
# something is wrong. we did not process the
|
|
# same number of channels as were reported.
|
|
$bad_grab = 1;
|
|
$total_bad_grabs++;
|
|
}
|
|
|
|
if ($DB) { print STDERR "$total_channels channels recieved out of $list_items reported.|$bad_grab|\n"; }
|
|
|
|
$chan_array_ref = \@chan_array;
|
|
|
|
# reload the settings from the DB at a fixed interval
|
|
$epoch = time();
|
|
if ( $epoch - $last_config_reload >= $settings_reload_interval )
|
|
{
|
|
# reload the server settings
|
|
$settings_ref = get_server_settings($dbhA,$server_ip);
|
|
%settings = %$settings_ref;
|
|
|
|
# reload the phone settings
|
|
$phones_ref = get_phones_settings($dbhA,$server_ip);
|
|
%phones = %$phones_ref;
|
|
|
|
$last_config_reload = time();
|
|
}
|
|
|
|
|
|
# update our time in the DB
|
|
$stmtA = "UPDATE server_updater set last_update=NOW() where server_ip='$server_ip'";
|
|
if($DB){print STDERR "\n$stmtA\n";}
|
|
$dbhA->do($stmtA);
|
|
|
|
# get the channels currently in the db
|
|
my ($db_trunks_ref, $db_clients_ref) = get_db_channels($dbhA,$server_ip);
|
|
|
|
# gather the various stats specific to the server stats
|
|
if ( $epoch - $last_stats_update >= $server_stats_update_interval )
|
|
{
|
|
$disk_usage = get_disk_space();
|
|
}
|
|
|
|
# gather the various stats specific to the performance log
|
|
if (( $settings_ref->{'sys_perf_log'} ) && ( $epoch - $last_perf_log >= $performance_logging_interval ))
|
|
{
|
|
( $mem_total, $mem_used, $mem_free ) = get_mem_usage();
|
|
$num_processes = get_num_processes();
|
|
( $reads, $writes ) = get_disk_rw();
|
|
}
|
|
|
|
# gather stats common to the performance log and server stats
|
|
if ( ( $epoch - $last_stats_update >= $server_stats_update_interval ) ||
|
|
(( $settings_ref->{'sys_perf_log'} ) && ( $epoch - $last_perf_log >= $performance_logging_interval )) )
|
|
{
|
|
$server_load = get_cpu_load();
|
|
|
|
(
|
|
$cpu_user_percent,
|
|
$cpu_idle_percent,
|
|
$cpu_sys_percent,
|
|
$cpu_vm_percent,
|
|
$user_diff,
|
|
$nice_diff,
|
|
$system_diff,
|
|
$idle_diff,
|
|
$iowait_diff,
|
|
$irq_diff,
|
|
$softirq_diff,
|
|
$steal_diff,
|
|
$guest_diff,
|
|
$guest_nice_diff
|
|
) = get_cpu_percent();
|
|
|
|
}
|
|
|
|
|
|
# check if there was something wrong with our channel grab
|
|
if ( $bad_grab )
|
|
{
|
|
if($DB){print STDERR "BAD GRAB!!!\n";}
|
|
|
|
# check if it is time to update the server stats
|
|
# if so use the old counts as the new ones are off
|
|
if ( $epoch - $last_stats_update >= $server_stats_update_interval )
|
|
{
|
|
server_stats_update( $dbhA, $server_ip, $old_counts, $server_load, $cpu_idle_percent, $disk_usage );
|
|
$last_stats_update = time();
|
|
}
|
|
|
|
# check if it is time to log the performance stats
|
|
# if so use the old counts as the new ones are off
|
|
if (( $settings_ref->{'sys_perf_log'} ) && ( $epoch - $last_perf_log >= $performance_logging_interval ))
|
|
{
|
|
server_perf_log( $dbhA, $server_ip, $old_counts, $server_load, $mem_free, $mem_used, $num_processes, $cpu_user_percent, $cpu_sys_percent, $cpu_idle_percent, $reads, $writes );
|
|
$last_perf_log = time();
|
|
}
|
|
|
|
usleep(10000); # sleep a hundreth of a second and try again
|
|
}
|
|
else
|
|
{
|
|
|
|
# Process the channel list
|
|
$counts = process_channels($dbhA,$chan_array_ref,$phones_ref,$db_trunks_ref,$db_clients_ref,$server_ip,$old_counts);
|
|
|
|
# make sure all the parked calls are valid
|
|
$parked_channels = validate_parked_channels( $dbhA, $parked_channels, $chan_array_ref, $server_ip );
|
|
|
|
# check if it is time to update the server stats
|
|
if ( $epoch - $last_stats_update >= $server_stats_update_interval )
|
|
{
|
|
server_stats_update( $dbhA, $server_ip, $counts, $server_load, $cpu_idle_percent, $disk_usage );
|
|
$last_stats_update = time();
|
|
}
|
|
|
|
# check if it is time to log the performance stats
|
|
if (( $settings_ref->{'sys_perf_log'} ) && ( $epoch - $last_perf_log >= $performance_logging_interval ))
|
|
{
|
|
server_perf_log( $dbhA, $server_ip, $counts, $server_load, $mem_free, $mem_used, $num_processes, $cpu_user_percent, $cpu_sys_percent, $cpu_idle_percent, $reads, $writes );
|
|
$last_perf_log = time();
|
|
}
|
|
|
|
# figure out how long that loop took.
|
|
# get the current time
|
|
( $now_sec, $now_micro_sec ) = gettimeofday();
|
|
|
|
# figure out how many micro seconds since epoch
|
|
$now_micro_epoch = $now_sec * 1000000;
|
|
$now_micro_epoch = $now_micro_epoch + $now_micro_sec;
|
|
|
|
$end_micro_epoch = $now_micro_epoch;
|
|
|
|
# subtract the current time in usec from time at the beginning of the loop
|
|
$loop_usec = $end_micro_epoch - $begin_micro_epoch;
|
|
|
|
# figure out how long to sleep
|
|
$sleep_usec = $loop_time_usec - $loop_usec;
|
|
|
|
# cannot sleep negative time
|
|
if ( $sleep_usec > 0 )
|
|
{
|
|
if ($DB) { print STDERR "loop took $loop_usec microseconds. sleeping for $sleep_usec microseconds to compensate\n"; }
|
|
|
|
# sleep it
|
|
usleep($sleep_usec);
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if($DB){print "DONE... Exiting... Goodbye... See you later... Not really, initiating next loop...$one_day_interval left\n";}
|
|
|
|
$event_string='HANGING UP|';
|
|
event_logger($SYSLOG,$event_string);
|
|
|
|
@hangup = $tn->cmd(String => "Action: Logoff\n\n", Prompt => "/.*/", Errmode => Return, Timeout => 1);
|
|
|
|
$tn->buffer_empty;
|
|
$tn->waitfor(Match => '/Message:.*\n\n/', Timeout => 10);
|
|
$ok = $tn->close;
|
|
|
|
|
|
$event_string='CLOSING DB CONNECTION|';
|
|
event_logger($SYSLOG,$event_string);
|
|
|
|
|
|
$dbhA->disconnect();
|
|
|
|
|
|
if($DB){print "DONE... Exiting... Goodbye... See you later... Really I mean it this time\n";}
|
|
|
|
|
|
exit;
|
|
|
|
|
|
sub process_channels
|
|
{
|
|
my ($dbhA,$chan_array_ref,$phones_ref,$db_trunks_ref,$db_clients_ref,$server_ip,$old_counts) = @_;
|
|
|
|
$client_insert_sql = "";
|
|
$client_insert_count = 0;
|
|
$client_delete_sql = "";
|
|
$client_delete_count = 0;
|
|
$trunk_insert_sql = "";
|
|
$trunk_insert_count = 0;
|
|
$trunk_delete_sql = "";
|
|
$trunk_delete_count = 0;
|
|
|
|
$counts->{'psuedo'} = 0;
|
|
$counts->{'total'} = 0;
|
|
$counts->{'trunks'} = 0;
|
|
$counts->{'clients'} = 0;
|
|
$counts->{'sip'} = 0;
|
|
$counts->{'iax'} = 0;
|
|
$counts->{'dahdi'} = 0;
|
|
$counts->{'local'} = 0;
|
|
$counts->{'other'} = 0;
|
|
|
|
%cid_chan_hash = {};
|
|
|
|
foreach $channel_ref (@$chan_array_ref)
|
|
{
|
|
$call_id = get_valid_callid($channel_ref->{'CallerIDName'},$channel_ref->{'ConnectedLineName'});
|
|
|
|
# only need to match local channels to real channels on VDAD and RINGAGENT calls
|
|
if ( (( $call_id =~ /^V\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d$/ ) && ( $channel_ref->{'ConnectedLineName'} ne "<unknown>" )) || ( $call_id =~ /^RINGAGENT/ ) )
|
|
{
|
|
if ( $channel_ref->{'Channel'} =~ /^Local/ )
|
|
{
|
|
$cid_chan_hash{"$call_id"}->{'channel'} = $channel_ref->{'Channel'};
|
|
$cid_chan_hash{"$call_id"}->{'uniqueid'} = $channel_ref->{'Uniqueid'};
|
|
$cid_chan_hash{"$call_id"}->{'linkedid'} = $channel_ref->{'Linkedid'};
|
|
$cid_chan_hash{"$call_id"}->{'calleridname'} = $channel_ref->{'CallerIDName'};
|
|
$cid_chan_hash{"$call_id"}->{'connectedlinename'} = $channel_ref->{'ConnectedLineName'};
|
|
}
|
|
else
|
|
{
|
|
$cid_chan_hash{"$call_id"}->{'dest_channel'} = $channel_ref->{'Channel'};
|
|
$cid_chan_hash{"$call_id"}->{'dest_uniqueid'} = $channel_ref->{'Uniqueid'};
|
|
$cid_chan_hash{"$call_id"}->{'linkedid'} = $channel_ref->{'Linkedid'};
|
|
$cid_chan_hash{"$call_id"}->{'calleridname'} = $channel_ref->{'CallerIDName'};
|
|
$cid_chan_hash{"$call_id"}->{'connectedlinename'} = $channel_ref->{'ConnectedLineName'};
|
|
}
|
|
}
|
|
|
|
|
|
$extension = $channel_ref->{'ApplicationData'};
|
|
$extension =~ s/^SIP\///gi; # remove "SIP/" from the beginning
|
|
$extension =~ s/-\S+$//gi; # remove everything after a -
|
|
$extension =~ s/\|.*//gi; # remove everything after the |
|
|
$extension =~ s/,.*//gi; # remove everything after the ,
|
|
|
|
# make sure the channel is a channel type we care about
|
|
if ( $channel_ref->{'Channel'} =~ /^IAX2|^SIP|^Local|^DAHDI/)
|
|
{
|
|
# assume all channels are trunks then check if they are not
|
|
$line_type = 'TRUNK';
|
|
|
|
$channel_match = $channel_ref->{'Channel'};
|
|
|
|
|
|
# Local channels are not considered trunks
|
|
if ( $channel_match =~ /^Local/)
|
|
{
|
|
$line_type = 'CLIENT';
|
|
$counts->{'local'}++;
|
|
$counts->{'clients'}++;
|
|
}
|
|
elsif ( $channel_match =~ /^IAX2/)
|
|
{
|
|
# clean up the channel to get the extension
|
|
$channel_match =~ s/\/\d+$|-\d+$//gi;
|
|
$channel_match =~ s/^IAX2\///gi;
|
|
$channel_match =~ s/\*/\\\*/gi;
|
|
|
|
# if the channels extension is in phones
|
|
# and it is and IAX phone then it is a client
|
|
if ( ( exists ( $phones_ref->{ $channel_match } ) ) && ( $phones_ref->{ $channel_match }->{'protocol'} eq 'IAX2' ) )
|
|
{
|
|
$line_type = 'CLIENT';
|
|
$counts->{'iax'}++;
|
|
$counts->{'clients'}++;
|
|
}
|
|
}
|
|
elsif ($channel_ref->{'Channel'} =~ /^SIP/)
|
|
{
|
|
# clean up the channel to get the extension
|
|
$channel_match =~ s/-\S+$//gi;
|
|
$channel_match =~ s/^SIP\///gi;
|
|
$channel_match =~ s/\*/\\\*/gi;
|
|
|
|
# if the channels extension is in phones
|
|
# and it is and SIP phone then it is a client
|
|
if ( ( exists ( $phones_ref->{ $channel_match } ) ) && ( $phones_ref->{ $channel_match }->{'protocol'} eq 'SIP' ) )
|
|
{
|
|
$line_type = 'CLIENT';
|
|
$counts->{'sip'}++;
|
|
$counts->{'clients'}++;
|
|
}
|
|
}
|
|
# no point logging pseudo channels, just increment the psuedo count
|
|
elsif ( $channel_ref->{'Channel'} =~ /^DAHDI\/pseudo/ )
|
|
{
|
|
$line_type = 'PSEUDO';
|
|
$counts->{'psuedo'}++;
|
|
}
|
|
|
|
elsif ($channel_ref->{'Channel'} =~ /^DAHDI/)
|
|
{
|
|
# clean up the channel to get the extension
|
|
$channel_match =~ s/^DAHDI\///gi;
|
|
$channel_match =~ s/\*/\\\*/gi;
|
|
|
|
# if the channels extension is in phones
|
|
# and it is and DAHDI/ZAP phone then it is a client
|
|
if ( ( exists ( $phones_ref->{ $channel_match } ) ) && ( $phones_ref->{$channel_match}->{'protocol'} =~ /^ZAP|^DAHDI/) )
|
|
{
|
|
$line_type = 'CLIENT';
|
|
$counts->{'dahdi'}++;
|
|
$counts->{'clients'}++;
|
|
}
|
|
}
|
|
|
|
# count what is left of the trunks
|
|
if ( $line_type eq 'TRUNK' ) { $counts->{'trunks'}++; }
|
|
|
|
}
|
|
else
|
|
{
|
|
$counts->{'other'}++;
|
|
}
|
|
|
|
# count the total we have processed
|
|
$counts->{'total'}++;
|
|
|
|
# process the CLIENTs first
|
|
if ( $line_type eq 'CLIENT' )
|
|
{
|
|
# check if the channel is in the DB already
|
|
$in_db = 0;
|
|
foreach $db_client ( @$db_clients_ref )
|
|
{
|
|
if ( ( $db_client->{'channel'} eq $channel_ref->{'Channel'} ) && ( $db_client->{'extension'} eq $extension ) )
|
|
{
|
|
if ($DBX) { print STDERR "marking $db_client->{'channel'} active in db_clients\n"; }
|
|
$in_db = 1; # not that the channel is in the DB
|
|
$db_client->{'active'} = 1; # mark that this channel is still active
|
|
last; # break out of this foreach loop
|
|
}
|
|
}
|
|
|
|
if ( $in_db )
|
|
{
|
|
# channel already exists in the DB
|
|
}
|
|
else
|
|
{
|
|
# Add this channel to the client insert
|
|
if ( $client_insert_count > 0 ) { $client_insert_sql .= ", \n\t" }
|
|
$client_insert_sql .= "('$channel_ref->{'Channel'}','$server_ip','$extension','$channel_ref->{'ApplicationData'}')";
|
|
$client_insert_count++;
|
|
}
|
|
}
|
|
|
|
# if not a client it must be a TRUNK
|
|
elsif ( $line_type eq 'TRUNK' )
|
|
{
|
|
# check if the channel is in the DB already
|
|
$in_db = 0;
|
|
foreach $db_trunk ( @$db_trunks_ref )
|
|
{
|
|
if ( ( $db_trunk->{'channel'} eq $channel_ref->{'Channel'} ) && ( $db_trunk->{'extension'} eq $extension) )
|
|
{
|
|
if ($DBX) { print STDERR "marking $db_trunk->{'channel'} active in db_trunks\n"; }
|
|
$in_db = 1; # not that the channel is in the DB
|
|
$db_trunk->{'active'} = 1; # mark that this channel is still active
|
|
last; # break out of this foreach loop
|
|
}
|
|
}
|
|
|
|
if ( $in_db )
|
|
{
|
|
# channel already exists in the DB
|
|
}
|
|
else
|
|
{
|
|
# Add this channel to the trunk insert
|
|
if ( $trunk_insert_count > 0 ) { $trunk_insert_sql .= ", \n\t"; }
|
|
$trunk_insert_sql .= "('$channel_ref->{'Channel'}','$server_ip','$extension','$channel_ref->{'ApplicationData'}')";
|
|
$trunk_insert_count++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( bad_grab_check( $counts, $old_counts ) )
|
|
{
|
|
if($DB){print STDERR "BAD GRAB!!!\n";}
|
|
|
|
usleep(10000); # sleep a hundreth of a second and try again
|
|
|
|
return $old_counts;
|
|
}
|
|
else
|
|
{
|
|
if ( $client_insert_count > 0 )
|
|
{
|
|
# insert all the new clients
|
|
my $stmtA = "INSERT INTO live_sip_channels (channel,server_ip,extension,channel_data) values \n\t" . $client_insert_sql;
|
|
if ($DB) { print STDERR "$stmtA\n"; }
|
|
$stmtA =~ s/\n|\t//gi;
|
|
$dbhA->do($stmtA);
|
|
}
|
|
elsif ($DB) { print STDERR "|no client channels to insert|\n"; }
|
|
|
|
if ( $trunk_insert_count > 0 )
|
|
{
|
|
# insert all the new trunks
|
|
my $stmtA = "INSERT INTO live_channels (channel,server_ip,extension,channel_data) values \n\t" . $trunk_insert_sql;
|
|
if ($DB) { print STDERR "$stmtA\n"; }
|
|
$stmtA =~ s/\n|\t//gi;
|
|
$dbhA->do($stmtA);
|
|
}
|
|
elsif ($DB) { print STDERR "|no trunk channels to insert|\n"; }
|
|
|
|
# find any clients that have hung up
|
|
foreach $db_client ( @$db_clients_ref )
|
|
{
|
|
# if DB client not in current channel list add it to the client delete
|
|
if ( ( !(exists( $db_client->{'active'} ) ) ) || ($db_client->{'active'} == 0 ) )
|
|
{
|
|
if ( $client_delete_count > 0 ) { $client_delete_sql .= " or \n\t"; }
|
|
$client_delete_sql .= "(server_ip='$server_ip' and channel='$db_client->{'channel'}' and extension='$db_client->{'extension'}')";
|
|
$client_delete_count++;
|
|
}
|
|
}
|
|
|
|
# find any trunks that have hung up
|
|
foreach $db_trunk ( @$db_trunks_ref )
|
|
{
|
|
# if DB trunk not in current channel list add it to the trunk delte
|
|
if ( ( !(exists( $db_trunk->{'active'} ) ) ) || ( $db_trunk->{'active'} == 0 ) )
|
|
{
|
|
if ( $trunk_delete_count > 0 ) { $trunk_delete_sql .= " or \n\t"; }
|
|
$trunk_delete_sql .= "(server_ip='$server_ip' and channel='$db_trunk->{'channel'}' and extension='$db_trunk->{'extension'}')";
|
|
$trunk_delete_count++;
|
|
}
|
|
}
|
|
|
|
# delete all the hung up clients
|
|
if ( $client_delete_count > 0 )
|
|
{
|
|
my $stmtA = "DELETE FROM live_sip_channels where \n\t(" . $client_delete_sql . " )";
|
|
if ($DB) { print STDERR "$stmtA\n"; }
|
|
$stmtA =~ s/\n|\t//gi;
|
|
$affected_rows = $dbhA->do($stmtA);
|
|
}
|
|
elsif ($DB) { print STDERR "|no client channels to delete|\n"; }
|
|
|
|
# delete all the hung up trunks
|
|
if ( $trunk_delete_count > 0 )
|
|
{
|
|
my $stmtA = "DELETE FROM live_channels where \n\t(" . $trunk_delete_sql . " )";
|
|
if ($DB) { print STDERR "$stmtA\n"; }
|
|
$stmtA =~ s/\n|\t//gi;
|
|
$affected_rows = $dbhA->do($stmtA);
|
|
}
|
|
elsif ($DB) { print STDERR "|no trunk channels to delete|\n"; }
|
|
|
|
# build the cid_channels_recent_$PADserver_ip insert
|
|
$cid_chan_sql = '';
|
|
$cid_chan_count = 0;
|
|
foreach $call_id (keys %cid_chan_hash)
|
|
{
|
|
if ( ( $cid_chan_hash{"$call_id"}->{'channel'} ne "" ) && ( $cid_chan_hash{"$call_id"}->{'dest_channel'} ne "" ) )
|
|
{
|
|
if ( $cid_chan_count > 0 ) { $cid_chan_sql .= ",\n\t"; }
|
|
$cid_chan_sql .= "( ";
|
|
$cid_chan_sql .= "'" . $cid_chan_hash{"$call_id"}->{'calleridname'} . "', ";
|
|
$cid_chan_sql .= "'" . $cid_chan_hash{"$call_id"}->{'connectedlinename'} . "', ";
|
|
# $cid_chan_sql .= "'$server_ip', ";
|
|
$cid_chan_sql .= "NOW(), ";
|
|
$cid_chan_sql .= "'" . $cid_chan_hash{"$call_id"}->{'channel'} . "', ";
|
|
$cid_chan_sql .= "'" . $cid_chan_hash{"$call_id"}->{'dest_channel'} . "', ";
|
|
$cid_chan_sql .= "'" . $cid_chan_hash{"$call_id"}->{'linkedid'} . "', ";
|
|
$cid_chan_sql .= "'" . $cid_chan_hash{"$call_id"}->{'uniqueid'} . "', ";
|
|
$cid_chan_sql .= "'" . $cid_chan_hash{"$call_id"}->{'dest_uniqueid'} . "'";
|
|
$cid_chan_sql .= " )";
|
|
$cid_chan_count++;
|
|
}
|
|
}
|
|
|
|
if ( $cid_chan_count > 0 )
|
|
{
|
|
# $stmtA = "INSERT IGNORE INTO cid_channels_recent (caller_id_name, connected_line_name, server_ip, call_date, channel, dest_channel, linkedid, dest_uniqueid, uniqueid) values \n\t";
|
|
$stmtA = "INSERT IGNORE INTO $cid_channels_recent (caller_id_name, connected_line_name, call_date, channel, dest_channel, linkedid, dest_uniqueid, uniqueid) values \n\t";
|
|
$stmtA .= $cid_chan_sql;
|
|
if ($DB) { print STDERR "$stmtA\n"; }
|
|
$stmtA =~ s/\n|\t//gi;
|
|
$dbhA->do($stmtA);
|
|
}
|
|
|
|
return $counts;
|
|
}
|
|
}
|
|
|
|
sub validate_parked_channels
|
|
{
|
|
( $dbhA, $parked_channels, $chan_array_ref, $server_ip ) = @_;
|
|
|
|
my $park_delete_sql = "";
|
|
my $park_delete_count = 0;
|
|
my $auto_delete_sql = "(";
|
|
|
|
# remove the duplicates caused by agents quickly parking, unparking, and parking again calls
|
|
$stmtA = "DELETE pc1 FROM parked_channels pc1, parked_channels pc2 WHERE pc1.parked_time < pc2.parked_time AND pc1.parked_time <> pc2.parked_time AND pc1.channel = pc2.channel AND pc1.server_ip='$server_ip' and pc2.server_ip='$server_ip'";
|
|
$deleted_rows = $dbhA->do($stmtA);
|
|
if ($DB) { print STDERR "Park Dup Del|$stmtA|$deleted_rows\n"; }
|
|
|
|
# get the channels currently parked
|
|
$stmtA = "SELECT channel,extension,parked_time,UNIX_TIMESTAMP(parked_time),channel_group FROM parked_channels where server_ip = '$server_ip' order by channel desc, parked_time desc;";
|
|
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
|
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
|
$sthArows=$sthA->rows;
|
|
$ref = $sthA->fetchall_arrayref;
|
|
|
|
# loop through the parked channels
|
|
foreach my $row ( @{ $ref } )
|
|
{
|
|
$channel = $row->[0];
|
|
$extension = $row->[1];
|
|
$parked_time = $row->[2];
|
|
$unix_parked_time = $row->[3];
|
|
$channel_group = $row->[4];
|
|
|
|
# check if we already saw the parked channel before
|
|
if ( exists( $parked_channels->{"$channel"} ) )
|
|
{
|
|
# if we have look for it in the current active channels
|
|
$channel_found = 0;
|
|
foreach $channel_ref (@$chan_array_ref)
|
|
{
|
|
# if we found it note that it there
|
|
if ( $channel_ref->{'Channel'} eq $channel ) { $channel_found = 1; }
|
|
}
|
|
|
|
# if it was found set its count back to 0
|
|
if ($channel_found) { $parked_channels->{"$channel"} = 0; }
|
|
# otherwise increment its count
|
|
else { $parked_channels->{"$channel"}++; }
|
|
}
|
|
else
|
|
{
|
|
# if not add it to our list and set the count to 0
|
|
$parked_channels->{"$channel"} = 0;
|
|
}
|
|
|
|
# if a channel has been gone for more than 10 seconds (25 calls to this function)
|
|
if ( $parked_channels->{"$channel"} >= 25 )
|
|
{
|
|
# build the SQL for deleting stale values
|
|
if ( $park_delete_count > 0 )
|
|
{
|
|
$park_delete_sql .= " or ";
|
|
$auto_delete_sql .= ", ";
|
|
}
|
|
$park_delete_sql .= "(channel='$channel' and extension='$extension')";
|
|
$auto_delete_sql .= "'$channel_group'";
|
|
$park_delete_count++;
|
|
}
|
|
}
|
|
|
|
$auto_delete_sql .= " )";
|
|
|
|
# if we have records to delete
|
|
if ( $park_delete_count > 0 )
|
|
{
|
|
# delete the records from parked_channels
|
|
$stmtA = "DELETE FROM parked_channels WHERE (" . $park_delete_sql . ") and server_ip='$server_ip'";
|
|
$deleted_rows = $dbhA->do($stmtA);
|
|
if ($DB) { print STDERR "Park Del|$stmtA|$deleted_rows\n"; }
|
|
|
|
# delete the records from vicidial_auto_calls
|
|
$stmtA = "DELETE FROM vicidial_auto_calls WHERE callerid IN " . $auto_delete_sql;
|
|
$deleted_rows = $dbhA->do($stmtA);
|
|
if ($DB) { print STDERR "Auto Calls Del|$stmtA|$deleted_rows\n"; }
|
|
}
|
|
|
|
return $parked_channels;
|
|
}
|
|
|
|
sub bad_grab_check
|
|
{
|
|
my ($counts,$old_counts) = @_;
|
|
my $bad_grab = 0;
|
|
|
|
# calculate the percentage of the total number of channels that changed
|
|
if ( (!$old_counts->{'total'}) or ($counts->{'total'} < 2) )
|
|
{$percent_total_static = 0;}
|
|
else
|
|
{
|
|
$percent_total_static = ( ($counts->{'total'} / $old_counts->{'total'}) * 100);
|
|
$percent_total_static = sprintf("%6.2f", $percent_total_static);
|
|
}
|
|
|
|
# calculate the percentage of DAHDI client channels that changed including pseudo channels
|
|
$current_dahdi = $counts->{'dahdi'} + $counts->{'pseudo'};
|
|
$old_dahdi = $old_counts->{'dahdi'} + $_oldcounts->{'pseudo'};
|
|
if ( (!$current_dahdi) or ($old_dahdi < 2) )
|
|
{$percent_dahdi_client_static = 0;}
|
|
else
|
|
{
|
|
$percent_dahdi_client_static = ( ($current_dahdi / $old_dahdi) * 100);
|
|
$percent_dahdi_client_static = sprintf("%6.2f", $percent_dahdi_client_static);
|
|
}
|
|
|
|
# calculate the percentage of IAX client channels that changed
|
|
if ( (!$counts->{'iax'}) or ($old_counts->{'iax'} < 2) )
|
|
{$percent_iax_client_static = 0;}
|
|
else
|
|
{
|
|
$percent_iax_client_static = ( ($counts->{'iax'} / $old_counts->{'iax'}) * 100);
|
|
$percent_iax_client_static = sprintf("%6.2f", $percent_iax_client_static);
|
|
}
|
|
|
|
# calculate the percentage of Local client channels that changed
|
|
if ( (!$counts->{'local'}) or ($old_counts->{'local'} < 2) )
|
|
{$percent_local_client_static = 0;}
|
|
else
|
|
{
|
|
$percent_local_client_static = ( ($counts->{'local'} / $old_counts->{'local'}) * 100);
|
|
$percent_local_client_static = sprintf("%6.2f", $percent_local_client_static);
|
|
}
|
|
|
|
# calculate the percentage of SIP client channels that changed
|
|
if ( (!$counts->{'sip'}) or ($old_counts->{'sip'} < 2) )
|
|
{$percent_sip_client_static = 0;}
|
|
else
|
|
{
|
|
$percent_sip_client_static = ( ($counts->{'sip'} / $old_counts->{'sip'}) * 100);
|
|
$percent_sip_client_static = sprintf("%6.2f", $percent_sip_client_static);
|
|
}
|
|
|
|
if ($DB) { print "BG_check_stats [$percent_total_static|$counts->{'total'}:$old_counts->{'total'}\t$percent_dahdi_client_static|$counts->{'dahdi'}:$old_counts->{'dahdi'}\t$percent_iax_client_static|$counts->{'iax'}:$old_counts->{'iax'}\t$percent_local_client_static|$counts->{'local'}:$old_counts->{'local'}\t$percent_sip_client_static|$counts->{'sip'}:$old_counts->{'sip'}]\n"; }
|
|
|
|
# MASSIVE IF STATEMENT FOR CHECKING IF IT WAS A BAD GRAB
|
|
if (
|
|
# if we had > 3 trunks or > 4 clients and we now have less than 10% of those remaining
|
|
( ($percent_total_static < 10) && ( ($old_counts->{'trunk'} > 3) or ($old_counts->{'client'} > 4) ) ) or
|
|
|
|
# or if we had > 10 trunks or > 10 clients and we now have less than 20% of those remaining
|
|
( ($percent_total_static < 20) && ( ($old_counts->{'trunk'} > 10) or ($old_counts->{'client'} > 10) ) ) or
|
|
|
|
# or if we had > 20 trunks or > 20 clients and we now have less than 30% of those remaining
|
|
( ($percent_total_static < 30) && ( ($old_counts->{'trunk'} > 20) or ($old_counts->{'client'} > 20) ) ) or
|
|
|
|
# or if we had > 30 trunks or > 30 clients and we now have less than 40% of those remaining
|
|
( ($percent_total_static < 40) && ( ($old_counts->{'trunk'} > 30) or ($old_counts->{'client'} > 30) ) ) or
|
|
|
|
# or if we had > 40 trunks or > 40 clients and we now have less than 50% of those remaining
|
|
( ($percent_total_static < 50) && ( ($old_counts->{'trunk'} > 40) or ($old_counts->{'client'} > 40) ) ) or
|
|
|
|
# or if we had > 3 dahdi clients and we now have less than 20% of those remaining
|
|
( ($percent_dahdi_client_static < 20) && ( $old_counts->{'dahdi'} > 3 ) ) or
|
|
|
|
# or if we had > 9 dahdi clients and we now have less than 40% of those remaining
|
|
( ($percent_dahdi_client_static < 40) && ( $old_counts->{'dahdi'} > 9 ) ) or
|
|
|
|
# or if we had > 3 iax clients and we now have less than 20% of those remaining
|
|
( ($percent_iax_client_static < 20) && ( $old_counts->{'iax'} > 3 ) ) or
|
|
|
|
# or if we had > 9 iax clients and we now have less than 40% of those remaining
|
|
( ($percent_iax_client_static < 40) && ( $old_counts->{'iax'} > 9 ) ) or
|
|
|
|
# or if we had > 3 sip clients and we now have less than 20% of those remaining
|
|
( ($percent_sip_client_static < 20) && ( $old_counts->{'sip'} > 3 ) ) or
|
|
|
|
# or if we had > 9 sip clients and we now have less than 40% of those remaining
|
|
( ($percent_sip_client_static < 40) && ( $old_counts->{'sip'} > 9 ) )
|
|
)
|
|
{
|
|
$bad_grab = 1;
|
|
$event_string="------ UPDATER BAD GRAB!!!\n$percent_total_static|$counts->{'total'}:$old_counts->{'total'}\t$percent_dahdi_client_static|$counts->{'dahdi'}:$old_counts->{'dahdi'}\t$percent_iax_client_static|$counts->{'iax'}:$old_counts->{'iax'}\t$percent_local_client_static|$counts->{'local'}:$old_counts->{'local'}\t$percent_sip_client_static|$counts->{'sip'}:$old_counts->{'sip'}\n";
|
|
&event_logger($SYSLOG,$event_string);
|
|
}
|
|
|
|
return $bad_grab;
|
|
}
|
|
|
|
|
|
|
|
sub server_stats_update
|
|
{
|
|
( $dbhA, $server_ip, $channel_counts, $server_load, $cpu_idle_percent, $disk_usage ) = @_;
|
|
|
|
$stmt = "UPDATE servers SET sysload='$server_load', channels_total='$channel_counts->{'total'}', cpu_idle_percent='$cpu_idle_percent', disk_usage='$disk_usage' where server_ip='$server_ip';";
|
|
$rows = $dbhA->do($stmt);
|
|
|
|
if ($DB)
|
|
{
|
|
print STDERR BRIGHT_RED BOLD, "\nServer Stats Updated", RESET;
|
|
print STDERR "|$stmt|$rows\n";
|
|
}
|
|
}
|
|
|
|
sub server_perf_log
|
|
{
|
|
( $dbhA, $server_ip, $channel_counts, $server_load, $mem_free, $mem_used, $num_processes, $cpu_user_percent, $cpu_sys_percent, $cpu_idle_percent, $reads, $writes ) = @_;
|
|
|
|
$stmt = "INSERT INTO server_performance (start_time, server_ip, sysload, freeram, usedram, processes, channels_total, trunks_total, clients_total, clients_zap, clients_iax, clients_local, clients_sip, live_recordings, cpu_user_percent, cpu_system_percent, cpu_idle_percent, disk_reads, disk_writes) values( NOW(), '$server_ip', '$server_load', '$mem_free', '$mem_used', '$num_processes', '$channel_counts->{'total'}', '$channel_counts->{'trunks'}', '$channel_counts->{'clients'}', '$channel_counts->{'dahdi'}', '$channel_counts->{'iax'}', '$channel_counts->{'local'}', '$channel_counts->{'sip'}', '0', '$cpu_user_percent', '$cpu_sys_percent', '$cpu_idle_percent', '$reads', '$writes')";
|
|
$dbhA->do($stmt);
|
|
if ($DB)
|
|
{
|
|
print STDERR BRIGHT_BLUE BOLD, "\nPerformance Log Record Inserted", RESET;
|
|
print STDERR "|$stmt\n\n";
|
|
}
|
|
}
|
|
|
|
|
|
sub get_server_settings
|
|
{
|
|
my ($dbhA,$server_ip) = @_;
|
|
|
|
### Grab Server values from the database
|
|
$stmtA = "SELECT sys_perf_log,vd_server_logs FROM servers where server_ip='$server_ip';";
|
|
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
|
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
|
$sthArows=$sthA->rows;
|
|
$settings_ref = $sthA->fetchrow_hashref;
|
|
|
|
if ( $settings_ref->{'sys_perf_log'} eq 'Y' ) { $settings_ref->{'sys_perf_log'} = 1;}
|
|
else { $settings_ref->{'sys_perf_log'} = 0;}
|
|
if ( $settings_ref->{'vd_server_logs'} eq 'Y' ) { $settings_ref->{'vd_server_logs'} = 1;}
|
|
else { $settings_ref->{'vd_server_logs'} = 0;}
|
|
|
|
return $settings_ref;
|
|
}
|
|
|
|
sub get_phones_settings
|
|
{
|
|
my ($dbhA,$server_ip) = @_;
|
|
|
|
$stmtA = "SELECT extension, protocol FROM phones where server_ip='$server_ip' and phone_type NOT LIKE \"%trunk%\"";
|
|
if($DB){print STDERR "|$stmtA|\n";}
|
|
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
|
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
|
$phones_ref = $sthA->fetchall_hashref('extension');
|
|
|
|
$zap_phones = 0;
|
|
$sip_phones = 0;
|
|
$iax_phones = 0;
|
|
|
|
$zap_phone_list = "|";
|
|
$sip_phone_list = "|";
|
|
$iax_phone_list = "|";
|
|
foreach $key ( sort (keys %$phones_ref) )
|
|
{
|
|
if ($DB) { print STDERR "$key|$phones_ref->{$key}->{'protocol'}\n"; }
|
|
|
|
if ( $phones_ref->{$key}->{'protocol'} eq 'ZAP' )
|
|
{
|
|
$zap_phones++;
|
|
$zap_phone_list .= "$key|";
|
|
}
|
|
elsif ( $phones_ref->{$key}->{'protocol'} eq 'SIP' )
|
|
{
|
|
$sip_phones++;
|
|
$sip_phone_list .= "$key|";
|
|
}
|
|
elsif ( $phones_ref->{$key}->{'protocol'} eq 'IAX' )
|
|
{
|
|
$iax_phones++;
|
|
$iax_phone_list .= "$keys|";
|
|
}
|
|
}
|
|
|
|
$phones_ref->{'zap_phones'} = $zap_phones;
|
|
$phones_ref->{'sip_phones'} = $sip_phones;
|
|
$phones_ref->{'iax_phones'} = $iax_phones;
|
|
$phones_ref->{'zap_phone_list'} = $zap_phone_list;
|
|
$phones_ref->{'sip_phone_list'} = $sip_phone_list;
|
|
$phones_ref->{'iax_phone_list'} = $iax_phone_list;
|
|
|
|
return $phones_ref;
|
|
}
|
|
|
|
sub get_db_channels
|
|
{
|
|
my ($dbhA,$server_ip) = @_;
|
|
|
|
my @db_trunks;
|
|
my @db_clients;
|
|
|
|
my $stmtA = "SELECT channel,extension FROM live_channels where server_ip='$server_ip';";
|
|
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
|
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
|
|
|
while ( $hash_ref = $sthA->fetchrow_hashref )
|
|
{
|
|
push( @db_trunks, $hash_ref );
|
|
}
|
|
|
|
my $stmtA = "SELECT channel,extension FROM live_sip_channels where server_ip='$server_ip';";
|
|
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
|
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
|
|
|
while ( $hash_ref = $sthA->fetchrow_hashref )
|
|
{
|
|
push( @db_clients, $hash_ref );
|
|
}
|
|
|
|
return (\@db_trunks, \@db_clients);
|
|
}
|
|
|
|
|
|
# function to validate whether a CID Name is a Vicidial Call ID that we care about
|
|
sub validate_cid_name
|
|
{
|
|
my ($cid_name) = @_;
|
|
|
|
# check if it is a valid CID Name
|
|
if (
|
|
( $cid_name =~ /DC\d\d\d\d\d\dW\d\d\d\d\d\d\d\d\d\dW/ ) || # 3way transfers
|
|
( $cid_name =~ /M\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d/) || # Manual Dials
|
|
( $cid_name =~ /V\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d/) || # Auto Dials
|
|
( $cid_name =~ /Y\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d/) || # Inbound Calls
|
|
( $cid_name =~ /^RINGAGENT/ )
|
|
)
|
|
{
|
|
return 1; # if so return 1 for true
|
|
}
|
|
else
|
|
{
|
|
return 0; # if not return 0 for false
|
|
}
|
|
|
|
}
|
|
|
|
# function to return the valid callid
|
|
sub get_valid_callid
|
|
{
|
|
my ( $CallerIDName, $ConnectedLineName ) = @_;
|
|
|
|
# remove everything after the space for Orex
|
|
if ( $CallerIDName =~ /\S\S\S\S\S\S\S\S\S\S\S\S\S\S\S\S\S\S/) {$CallerIDName =~ s/ .*//gi;}
|
|
if ( $ConnectedLineName =~ /\S\S\S\S\S\S\S\S\S\S\S\S\S\S\S\S\S\S/) {$ConnectedLineName =~ s/ .*//gi;}
|
|
|
|
# if the CallerIDName variable does not have a valid Vicidial Call ID
|
|
# but the ConnectedLineName does use the ConnectedLineName
|
|
if ( !(validate_cid_name($CallerIDName)) && (validate_cid_name($ConnectedLineName)) )
|
|
{
|
|
return $ConnectedLineName;
|
|
}
|
|
else
|
|
{
|
|
return $CallerIDName;
|
|
}
|
|
}
|
|
|
|
|
|
sub event_logger
|
|
{
|
|
my ($SYSLOG,$event_string) = @_;
|
|
if ($SYSLOG)
|
|
{
|
|
### open the log file for writing ###
|
|
open(Lout, ">>$PATHlogs/update.$action_log_date")
|
|
|| die "Can't open $PATHlogs/update.$action_log_date: $!\n";
|
|
print Lout "$now_date|$event_string|\n";
|
|
close(Lout);
|
|
}
|
|
$event_string='';
|
|
}
|
|
|
|
|
|
|
|
# subroutine to parse the asterisk version
|
|
# and return a hash with the various part
|
|
sub parse_asterisk_version
|
|
{
|
|
# grab the arguments
|
|
my $ast_ver_str = $_[0];
|
|
|
|
# get everything after the - and put it in $ast_ver_postfix
|
|
my @hyphen_parts = split( /-/ , $ast_ver_str );
|
|
|
|
my $ast_ver_postfix = $hyphen_parts[1];
|
|
|
|
# now split everything before the - up by the .
|
|
my @dot_parts = split( /\./ , $hyphen_parts[0] );
|
|
|
|
my %ast_ver_hash;
|
|
|
|
if ( $dot_parts[0] <= 1 )
|
|
{
|
|
%ast_ver_hash = (
|
|
"major" => $dot_parts[0],
|
|
"minor" => $dot_parts[1],
|
|
"build" => $dot_parts[2],
|
|
"revision" => $dot_parts[3],
|
|
"postfix" => $ast_ver_postfix
|
|
);
|
|
}
|
|
|
|
# digium dropped the 1 from asterisk 10 but we still need it
|
|
if ( $dot_parts[0] > 1 )
|
|
{
|
|
%ast_ver_hash = (
|
|
"major" => 1,
|
|
"minor" => $dot_parts[0],
|
|
"build" => $dot_parts[1],
|
|
"revision" => $dot_parts[2],
|
|
"postfix" => $ast_ver_postfix
|
|
);
|
|
}
|
|
|
|
return ( %ast_ver_hash );
|
|
}
|
|
|
|
sub get_time_now #get the current date and time and epoch for logging call lengths and datetimes
|
|
{
|
|
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
|
|
$year = ($year + 1900);
|
|
$mon++;
|
|
if ($mon < 10) {$mon = "0$mon";}
|
|
if ($mday < 10) {$mday = "0$mday";}
|
|
if ($hour < 10) {$hour = "0$hour";}
|
|
if ($min < 10) {$min = "0$min";}
|
|
if ($sec < 10) {$sec = "0$sec";}
|
|
|
|
$now_date_epoch = time();
|
|
$now_date = "$year-$mon-$mday $hour:$min:$sec";
|
|
$action_log_date = "$year-$mon-$mday";
|
|
}
|
|
|
|
|
|
# try to load a module
|
|
sub try_load
|
|
{
|
|
my $mod = shift;
|
|
|
|
eval("use $mod");
|
|
|
|
if ($@)
|
|
{
|
|
#print "\$@ = $@\n";
|
|
return(0);
|
|
}
|
|
else
|
|
{
|
|
return(1);
|
|
}
|
|
}
|
|
|
|
|
|
sub print_now
|
|
{
|
|
my $string = shift;
|
|
|
|
# get the current time in microseconds
|
|
my ( $now_sec, $now_micro_sec ) = gettimeofday();
|
|
|
|
# figure out how many micro seconds since epoch
|
|
my $now_micro_epoch = $now_sec * 1000000;
|
|
$now_micro_epoch = $now_micro_epoch + $now_micro_sec;
|
|
|
|
print "\n$string|$now_micro_epoch\n\n";
|
|
}
|
|
|
|
sub get_cpu_percent
|
|
{
|
|
# stat file in proc
|
|
$stat = '/proc/stat';
|
|
|
|
# read it
|
|
open( FH , "<$stat" );
|
|
@lines = <FH>;
|
|
close( FH );
|
|
|
|
# get the various times spent doing stuff ( $cpu is useless )
|
|
($cpu, $user, $nice, $system, $idle, $iowait, $irq, $softirq, $steal, $guest, $guest_nice ) = split( ' ', $lines[0] );
|
|
|
|
# total the different catagories of time
|
|
$cpu_user = $user + $nice;
|
|
$cpu_idle = $idle + $iowait;
|
|
$cpu_sys = $system + $irq + $softirq;
|
|
$cpu_vm = $steal + $guest + $guest_nice;
|
|
|
|
# check if we have previous values
|
|
if ( defined ( $prev_user ) )
|
|
{
|
|
# get the differential from last time
|
|
$cpu_user_diff = $cpu_user - $prev_cpu_user;
|
|
$cpu_idle_diff = $cpu_idle - $prev_cpu_idle;
|
|
$cpu_sys_diff = $cpu_sys - $prev_cpu_sys;
|
|
$cpu_vm_diff = $cpu_vm - $prev_cpu_vm;
|
|
|
|
$user_diff = $user - $prev_user;
|
|
$nice_diff = $nice - $prev_nice;
|
|
$system_diff = $system - $prev_system;
|
|
$idle_diff = $idle - $prev_idle;
|
|
$iowait_diff = $iowait - $prev_iowait;
|
|
$irq_diff = $irq - $prev_irq;
|
|
$softirq_diff = $softirq - $prev_softirq;
|
|
$steal_diff = $steal - $prev_steal;
|
|
$guest_diff = $guest - $prev_guest;
|
|
$guest_nice_diff = $guest_nice - $prev_guest_nice;
|
|
|
|
# total the differentials
|
|
$cpu_total_diff = $cpu_user_diff + $cpu_idle_diff + $cpu_sys_diff + $cpu_vm_diff;
|
|
|
|
$cpu_user_percent = sprintf("%.0f", (( $cpu_user_diff / $cpu_total_diff ) * 100 ));
|
|
$cpu_idle_percent = sprintf("%.0f", (( $cpu_idle_diff / $cpu_total_diff ) * 100 ));
|
|
$cpu_sys_percent = sprintf("%.0f", (( $cpu_sys_diff / $cpu_total_diff ) * 100 ));
|
|
$cpu_vm_percent = sprintf("%.0f", (( $cpu_vm_diff / $cpu_total_diff ) * 100 ));
|
|
}
|
|
else
|
|
{
|
|
# first time runnings so there are no previous values.
|
|
# all we can do is base it off the system totals since boot.
|
|
$cpu_total = $cpu_user + $cpu_idle + $cpu_sys + $cpu_vm;
|
|
|
|
$cpu_user_percent = sprintf("%.0f", (( $cpu_user / $cpu_total ) * 100 ));
|
|
$cpu_idle_percent = sprintf("%.0f", (( $cpu_idle / $cpu_total ) * 100 ));
|
|
$cpu_sys_percent = sprintf("%.0f", (( $cpu_sys / $cpu_total ) * 100 ));
|
|
$cpu_vm_percent = sprintf("%.0f", (( $cpu_vm / $cpu_total ) * 100 ));
|
|
}
|
|
|
|
# store the values for the next call
|
|
$prev_user = $user;
|
|
$prev_nice = $nice;
|
|
$prev_system = $system;
|
|
$prev_idle = $idle;
|
|
$prev_iowait = $iowait;
|
|
$prev_irq = $irq;
|
|
$prev_softirq = $softirq;
|
|
$prev_steal = $steal;
|
|
$prev_guest = $guest;
|
|
$prev_guest_nice = $guest_nice;
|
|
$prev_cpu_user = $cpu_user;
|
|
$prev_cpu_idle = $cpu_idle;
|
|
$prev_cpu_sys = $cpu_sys;
|
|
$prev_cpu_vm = $cpu_vm;
|
|
|
|
|
|
return (
|
|
$cpu_user_percent,
|
|
$cpu_idle_percent,
|
|
$cpu_sys_percent,
|
|
$cpu_vm_percent,
|
|
$user_diff,
|
|
$nice_diff,
|
|
$system_diff,
|
|
$idle_diff,
|
|
$iowait_diff,
|
|
$irq_diff,
|
|
$softirq_diff,
|
|
$steal_diff,
|
|
$guest_diff,
|
|
$guest_nice_diff
|
|
);
|
|
}
|
|
|
|
sub get_cpu_load
|
|
{
|
|
$lavg = '/proc/loadavg';
|
|
|
|
open( FH , "<$lavg" );
|
|
@lines = <FH>;
|
|
close( FH );
|
|
|
|
$server_load = $lines[0];
|
|
$server_load =~ s/ .*//gi;
|
|
$server_load =~ s/\D//gi;
|
|
|
|
return $server_load;
|
|
}
|
|
|
|
sub get_mem_usage
|
|
{
|
|
$meminfo = '/proc/meminfo';
|
|
|
|
open( FH , "<$meminfo" );
|
|
@lines = <FH>;
|
|
close( FH );
|
|
|
|
$mem_total = $lines[0];
|
|
$mem_total =~ s/MemTotal: *//g;
|
|
|
|
$mem_free = $lines[1];
|
|
$mem_free =~ s/MemFree: *//g;
|
|
|
|
$mem_used = $mem_total - $mem_free;
|
|
|
|
$mem_used = floor( $mem_used / 1024 );
|
|
$mem_total = floor( $mem_total / 1024 );
|
|
$mem_free = floor( $mem_free / 1023 );
|
|
|
|
return ( $mem_total, $mem_used, $mem_free );
|
|
|
|
}
|
|
|
|
sub get_disk_space
|
|
{
|
|
@serverDISK = `$dfbin -B 1048576 -x nfs -x cifs -x sshfs -x ftpfs`;
|
|
$ct=0;
|
|
$ct_PCT=0;
|
|
$disk_usage = '';
|
|
foreach(@serverDISK)
|
|
{
|
|
if ($serverDISK[$ct] =~ /(\d+\%)/)
|
|
{
|
|
$ct_PCT++;
|
|
$usage = $1;
|
|
$usage =~ s/\%//gi;
|
|
$disk_usage .= "$ct_PCT $usage|";
|
|
}
|
|
$ct++;
|
|
}
|
|
|
|
return $disk_usage;
|
|
}
|
|
|
|
sub get_num_processes
|
|
{
|
|
$num_processes = 0;
|
|
|
|
opendir( DH, '/proc');
|
|
while ( readdir( DH ) )
|
|
{
|
|
if ( looks_like_number( $_ ) ) { $num_processes++; }
|
|
}
|
|
closedir( DH );
|
|
|
|
return ($num_processes);
|
|
}
|
|
|
|
|
|
sub get_disk_rw
|
|
{
|
|
$total_reads = 0;
|
|
$total_writes = 0;
|
|
|
|
$diskstats = "/proc/diskstats";
|
|
|
|
open( FH , "<$diskstats" );
|
|
@lines = <FH>;
|
|
close( FH );
|
|
|
|
foreach $line ( @lines )
|
|
{
|
|
# remove excess white space
|
|
$line =~ s/\h+/ /g;
|
|
$line =~ s/^\s+|\s+$//g;
|
|
|
|
# split the line
|
|
(
|
|
$major,
|
|
$minor,
|
|
$device,
|
|
$reads_completed,
|
|
$reads_merged,
|
|
$sectors_read,
|
|
$time_reading,
|
|
$writes_completed,
|
|
$writes_merged,
|
|
$sectors_written,
|
|
$time_writing,
|
|
$current_ios,
|
|
$ios_time,
|
|
$weighted_ios_time
|
|
) = split( ' ', $line );
|
|
|
|
# check if device is a drive or partition or raid
|
|
if ( $device !~ /\d/ )
|
|
{
|
|
$total_reads += $sectors_read;
|
|
$total_writes += $sectors_written;
|
|
}
|
|
}
|
|
|
|
# check if we previously got the total reads
|
|
if ( defined ( $prev_total_reads ) )
|
|
{
|
|
$reads = $total_reads - $prev_total_reads;
|
|
$writes = $total_writes - $prev_total_writes;
|
|
}
|
|
else
|
|
{
|
|
# cannot figure out the difference
|
|
# if we don't know what it was before
|
|
$reads = 0;
|
|
$writes = 0;
|
|
}
|
|
|
|
$prev_total_reads = $total_reads;
|
|
$prev_total_writes = $total_writes;
|
|
|
|
return ( $reads, $writes );
|
|
}
|