#!/usr/bin/perl # check_ast_chans.pl - Icinga plugin to check total asterisk channel usage # # Copyright (C) 2018 James Pearson LICENSE: AGPLv2 # ### All my lovely little modules use warnings; use Net::Telnet (); use Getopt::Long; # Nagios specific use lib "/usr/lib/nagios/plugins"; our $TIMEOUT; our %ERRORS; eval 'use utils qw(%ERRORS $TIMEOUT)'; if ($@) { $TIMEOUT = 30; %ERRORS = ('OK'=>0,'WARNING'=>1,'CRITICAL'=>2,'UNKNOWN'=>3,'DEPENDENT'=>4); } my $version='1.0'; ### Set-up some useful defaults $DB=0; $channel_warn = 0; $channel_crit = 0; $asterisk_host = "127.0.0.1"; $asterisk_port = "5038"; $asterisk_user = "cron"; $asterisk_pass = "1234"; $timeout = 3; $return_code = 3; # By default, our return state is unknown unless specifically set otherwise $return_perf_data = 0; $max_chan_ct=450; $min_chan_ct=0; sub debugoutput { # I got tired of repeating this code snippet, so this gives debug output, with optional critical die my $debugline = shift; my $debugdie = 0; $debugdie = shift; if ($DB==1 and $debugdie==0) { # We are just giving output, nothing more print "$debugline\n"; } elsif ($DB==1 and $debugdie==1) { # Evidently it was a critical error, so we die on output die("$debugline\n"); } } sub usage { print "\n\nAsterisk channel monitoring through AMI for Nagios/Icinga\n\n"; print "allowed run time options:\n"; print " [-H $asterisk_host] = Asterisk Host or IP\n"; print " [-U $asterisk_user] = AMI Username\n"; print " [-P $asterisk_pass] = AMI Password\n"; print " [-p $asterisk_port] = AMI port\n"; print " [-w $channel_warn] = Warning Level, none if not specified\n"; print " [-c $channel_crit] = Critical Level, none if not specified\n"; print " [-t $timeout] = Timeout to wait for AMI connection\n"; print " [-f] = Return performance data\n"; print " [--debug] = Debug Output for testing\n"; print " [--help] = This help screen\n"; exit $ERRORS{'UNKNOWN'}; } Getopt::Long::Configure('bundling', 'no_ignore_case'); GetOptions( 'host|H=s' => \$asterisk_host, 'user|U=s' => \$asterisk_user, 'pass|P=s' => \$asterisk_pass, 'port|p=i' => \$asterisk_port, 'warn|w=i' => \$channel_warn, 'crit|c=i' => \$channel_crit, 'timeout|t=i' => \$timeout, 'f' => \$return_perf_data, 'debug' => \$DB, 'help' => sub { &usage(); }, ); if ($channel_warn>0 or $channel_crit>0 ) { if ($channel_warn==0 or $channel_crit==0) { print "Warning and Critical must both be specified!\n"; exit $ERRORS{'UNKNOWN'}; } if ($channel_warn > $channel_crit) { print "Critical level must be higher then Warning level!\n"; exit $ERRORS{'UNKNOWN'}; } } if ($DB==1) { print "\n\nAsterisk channel monitoring through AMI for Nagios/Icinga\n\n"; print "\n----- DEBUG -----\n\n"; print " Host: $asterisk_host\n"; print " User: $asterisk_user\n"; print " Pass: $asterisk_pass\n"; print " Port: $asterisk_port\n"; print " Time: $timeout\n"; if ($channel_warn>0 or $channel_crit>0) { print " Warn: $channel_warn\n"; print " Crit: $channel_crit\n"; } else { print " Not checking for warn/crit\n"; } if ($return_perf_data==1) { print " Perf: Enabled\n";} } # Lets login $t = new Net::Telnet (Port => $asterisk_port, Timeout => $timeout, Prompt => '/.*[\$%#>] $/', Output_record_separator => '', Errmode => 'return' ); #$fh = $t->dump_log("$telnetlog"); # uncomment for telnet log # Login to the AMI and get our channel list $t->open("$asterisk_host"); if ($t->errmsg) { print "Could not connect to Asterisk!\n"; exit $ERRORS{'UNKNOWN'}; } $t->waitfor('/[0123]\n$/'); # print login if ($t->errmsg) { print "Login Prompt not Received!\n"; exit $ERRORS{'UNKNOWN'}; } $t->print("Action: Login\nUsername: $asterisk_user\nSecret: $asterisk_pass\n\n"); if ($t->errmsg) { print "Login Information Incorrect!\n"; exit $ERRORS{'UNKNOWN'}; } $t->waitfor('/Authentication accepted/'); # waitfor auth accepted if ($t->errmsg) { print "Command not Accepted!\n"; exit $ERRORS{'UNKNOWN'};} @list_channels = $t->cmd(String => "Action: Status\n\n", Prompt => '/Event: StatusComplete.*/'); $t->print("Action: Logoff\n\n"); $t->close; # Now loop through the channel listing and figure out what we got $test_zap_count=0; $test_iax_count=0; $test_local_count=0; $test_sip_count=0; $active_channels = 0; $s=0; foreach(@list_channels) { if ($list_channels[$s] =~ /^Channel: SIP/) {$test_sip_count++; $active_channels++; debugoutput("Found SIP Channel",0);} if ($list_channels[$s] =~ /^Channel: Local/) {$test_local_count++; $active_channels++; debugoutput("Found Local Channel",0);} if ($list_channels[$s] =~ /^Channel: IAX2/) {$test_iax_count++; $active_channels++; debugoutput("Found IAX Channel",0);} if ($list_channels[$s] =~ /^Channel: ZAP/) {$test_zap_count++; $active_channels++; debugoutput("Found ZAP/DAHDI Channel",0);} if ($list_channels[$s] =~ /^Channel: DAHDI/) {$test_zap_count++; $active_channels++; debugoutput("Found ZAP/DAHDI Channel",0);} #debugoutput("Channel Line: $list_channels[$s]",0) $s++; } $return_string = "Active: $active_channels , SIP: $test_sip_count , IAX: $test_iax_count , ZAP/DAH: $test_zap_count, Local: $test_local_count"; debugoutput("Init Channel Return String: $return_string",0); # Do our crit/warning checking and perfdata processing if ($s>0) { $return_code=0; } # Basically, if we had any output then we got a channel listing, even if no channels if ($channel_warn>0 && $active_channels>$channel_warn) { $return_code=1;} if ($channel_crit>0 && $active_channels>$channel_crit) { $return_code=2;} if ($return_perf_data==1) { if ($channel_warn > 0) { $return_string = $return_string . " | astchannels=$active_channels;$channel_warn;$channel_crit;$min_chan_ct;$max_chan_ct"; } else { $return_string = $return_string . " | channels=$active_channels"; } debugoutput("Perf Channel Return String: $return_string",0); } if ($return_code==0) { $return_string = "OK : " . $return_string; print "$return_string\n"; exit $ERRORS{'OK'};} if ($return_code==1) { $return_string = "WARNING : " . $return_string; print "$return_string\n"; exit $ERRORS{'WARNING'};} if ($return_code==2) { $return_string = "CRITICAL : " . $return_string; print "$return_string\n"; exit $ERRORS{'CRITICAL'};}