Created
February 27, 2013 22:16
-
-
Save andrius/5052336 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
require 'monitor' | |
require 'pp' | |
require 'timeout' | |
require 'time' | |
require 'pp' | |
require 'rubygems' | |
require 'AGIServer' | |
# this script work with installed to /usr/sbin astcli app i.e. from | |
# /usr/src/asterisk/asterisk-1.6.2.6/contrib/scripts/astcli | |
# and enabled asterisk manager user with permission to execute commands and originate | |
# in /etc/asterisk/manager.conf, user must be allowed for 127.0.0.1 | |
# | |
# in extensions_custom put: | |
# [check-system-status] | |
# exten => request,1,NoCDR | |
# exten => request,n,Answer | |
# exten => request,n,Wait(180) | |
# | |
# If call are unsuccesful or astcli cannot connect to asterisk, it will be restarted via | |
# /etc/init.d/asterisk command. 20 seconds later command 'asterisk' will be executed under root user, | |
# so if /etc/init.d/asterisk not-exists or failed, there are other chance to start system. | |
# | |
# Since asterisk processes may be started as different users and from different folters, | |
# such processes will be killed during restart (can be modified in kill_processes command): | |
$in_debug_mode = true | |
# timeout in seconds for AGI (for debug should be higher value) | |
TIMEOUT = 5 | |
# check interval (in seconds) | |
CHECK_INTERVAL = 120 | |
# service we monitor and restart | |
SERVICE = 'asterisk' | |
SEND_EMAIL_TO = '[email protected]' | |
$call_status = :never_received | |
# tiny FastAGI class, answer the call and setup global variable | |
class Call < AGIRoute | |
def register | |
begin | |
agi.answer | |
agi.exec "NoOp \"Call received, recorded, thanks!\"" | |
$call_status = :answered | |
agi.exec "Busy 8" | |
rescue => err | |
pp err.backtrace | |
end | |
end | |
end | |
class CallServer | |
class << self | |
def start | |
puts "#{Time.now} call tester started" | |
begin | |
unless defined?(@@server) | |
@@logger = Logger.new(STDERR) | |
@@logger.level = $in_debug_mode ? Logger::DEBUG : Logger::FATAL | |
@@server = AGIServer.new :bind_port => 30303, :bind_host => '127.0.0.1', | |
:min_workers => 2, :max_workers => 2, :jobs_per_worker => 2, | |
:logger => @@logger, :stats => false | |
@@server.start | |
end | |
rescue => err | |
pp err.backtrace | |
end | |
end | |
def stop | |
begin | |
sleep 10 | |
@@server.shutdown if defined?(@@server) | |
puts "#{Time.now} call tester stopped" | |
rescue => err | |
pp err.backtrace | |
end | |
end | |
end | |
end | |
class PhoneSystem | |
class << self | |
def verbose? | |
ARGV[0] == 'silent' ? false : true | |
end | |
def send_by_email? | |
ARGV[0] == 'sendemail' ? true : false | |
end | |
def words_to_seconds(args) | |
args[:days].to_i * 86400 + args[:hours].to_i * 3600 + args[:minutes].to_i * 60 + args[:seconds].to_i | |
end | |
def system_name | |
@@system_name ||= File.read('/etc/asterisk/asterisk.conf').split(/\n/).delete_if { |item| !item.match(/^systemname/i) }[-1].split(/=|;/)[1].strip rescue "" | |
@@system_name | |
end | |
def hostname | |
@@hostname ||= `hostname`.chomp.strip | |
@@hostname | |
end | |
def get_asterisk_manager_credentials(params = {:filename => '/etc/asterisk/manager.conf'}) | |
manager_data = `sudo cat #{params[:filename]} | grep -v '\\[general' | grep '\\[' -A 4` | |
if manager_data =~ /\[(.+)\][^secret]*secret\s*=\s*(.*)/ then | |
[$1, $2] | |
else | |
[nil, nil] | |
end | |
end | |
def db_access | |
$db_access_data ||= {} | |
if $db_access_data.empty? then | |
`cat /etc/asterisk/res_mysql.conf | grep '=' | grep -v '^;'`.split("\n").each do |rec| | |
k,v = rec.split('=') | |
$db_access_data[k.strip.to_sym] = v.strip | |
end | |
end | |
$db_access_data | |
end | |
def astcli | |
unless defined?(@@manager_username) | |
@@manager_username, @@manager_secret = get_asterisk_manager_credentials | |
end | |
"sudo astcli -u #{@@manager_username} -s #{@@manager_secret}" | |
end | |
def kill_processes(process_name) | |
filter = `ps axw | grep #{process_name} | grep -v 'grep\\|restart_\\|call\\|log\\|etc' | awk '{print $1}' | xargs` | |
if $in_debug_mode | |
pp `ps axw | grep #{process_name} | grep -v 'grep\\|restart_\\|call\\|log\\|etc'` | |
else | |
processes = filter.strip.chomp.strip | |
`sudo kill -9 #{processes} 2>&1 > /dev/null` unless processes == "" | |
end | |
end | |
def stop_asterisk | |
kill_processes 'safe_asterisk' | |
kill_processes 'asterisk' | |
kill_processes 'mpg123' | |
sql = "update sip_accounts set regserver = null, useragent = null, regseconds = 0, port = 0, ipaddr = null, fullcontact = '' where regserver = '#{system_name}'" | |
if $in_debug_mode then | |
puts sql | |
else | |
sleep 3 | |
`sudo /etc/init.d/asterisk stop` | |
`sudo mysql -h\"#{db_access[:dbhost]}\" -u\"#{db_access[:dbuser]}\" -p\"#{db_access[:dbpass]}\" -D\"#{db_access[:dbname]}\" -e\"#{sql}\"` | |
sleep 3 | |
end | |
end | |
def start_asterisk | |
unless $in_debug_mode | |
`sudo /etc/init.d/asterisk start` | |
sleep 20 | |
`sudo asterisk` | |
end | |
end | |
def restart_asterisk | |
stop_asterisk | |
start_asterisk | |
end | |
def sendmail(params) | |
server_status = params[:status] || "unreacheable" | |
message = params[:message] | |
`echo "#{'DEBUG MODE!!! ' if $in_debug_mode}#{message}" | mail -s "[ERR] Asterisk PBX #{system_name} is #{server_status}" #{SEND_EMAIL_TO}` | |
end | |
def execute_asterisk_command(command) | |
result, exitstatus = Timeout.timeout(5) do | |
begin | |
[`#{astcli} '#{command}' 2>&1`, $?.exitstatus.to_i] | |
rescue Exception | |
['Request timeout', 1] | |
rescue Timeout::Error | |
['Request timeout', 1] | |
rescue | |
['Request timeout', 1] | |
end | |
end | |
if result =~ /Authentication failed|Request timeout|Could not connect to Host:/ then | |
restart_asterisk | |
sendmail :status => :unreacheable, :message => "Asterisk manager problem: #{result.chomp.strip}. Asterisk are restarted" | |
# exit # cannot exit in daemons! wait instead | |
sleep 5 | |
end | |
result.chomp.strip | |
end | |
def wait_for_call(params) | |
start_time = Time.now | |
loop do | |
puts "Waiting for callback result, current is #{$call_status}" if $in_debug_mode | |
break :timeout if ( Time.now - start_time ) > params[:timeout] | |
break $call_status unless $call_status == :never_received | |
sleep 2 | |
end | |
end | |
def send_three_calls | |
1.upto(3) do |attempt_no| | |
break :call_status if $call_status == :answered | |
puts "#{Time.now} sending call attempt # #{attempt_no}, current call status is #{$call_status}." | |
execute_asterisk_command "originate Local/request@check-system-status application AGI 'agi://localhost:30303/Call/register'" | |
#execute_asterisk_command "originate Local/request@check-system-status extension register@check-system-status" | |
result = wait_for_call :timeout => TIMEOUT | |
puts "#{Time.now} call status after test is #{$call_status} / #{result} (attempt #: #{attempt_no})" | |
break :call_status if $call_status == :answered | |
end | |
end | |
def check_status | |
puts "checking status" if $in_debug_mode | |
send_three_calls | |
unless $call_status == :answered then | |
stop_asterisk | |
start_asterisk | |
sendmail :status => :frozen, :message => "Asterisk does not accept calls, restarted it" | |
end | |
end | |
end | |
end | |
def test | |
puts PhoneSystem::system_name | |
puts PhoneSystem::hostname | |
pp PhoneSystem::get_asterisk_manager_credentials | |
pp PhoneSystem::db_access | |
puts PhoneSystem::execute_asterisk_command "core show uptime" | |
CallServer::start | |
puts PhoneSystem::check_status | |
puts $call_status | |
CallServer::stop | |
exit | |
end | |
def run_it | |
CallServer::start | |
trap("INT") { CallServer::stop } | |
trap("TRAP") { CallServer::stop } | |
PhoneSystem::check_status | |
CallServer::stop | |
end | |
if $in_debug_mode then | |
test | |
else | |
run_it | |
end | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment