#!/usr/bin/env ruby
Process.setproctitle($0)

require File.expand_path('../../lib/riemann/tools', __FILE__)

class Riemann::Tools::FreeSWITCH
  include Riemann::Tools

  opt :calls_warning, "Calls warning threshold", :default => 100
  opt :calls_critical, "Calls critical threshold", :default => 300
  opt :pid_file, "FreeSWITCH daemon pidfile", :type => String, :default => "/var/run/freeswitch/freeswitch.pid"

  def initialize
    @limits = {
      :calls => {:critical => opts[:calls_critical], :warning => opts[:calls_warning]}
    }
  end

  def dead_proc?(pid)
    begin
      Process.getpgid(pid)
      false
    rescue Errno::ESRCH
      true
    end
  end

  def alert(service, state, metric, description)
    report(
      :service => service.to_s,
      :state => state.to_s,
      :metric => metric.to_f,
      :description => description
    )
  end

  def exec_with_timeout(cmd, timeout)
    pid = Process.spawn(cmd, {[:err,:out] => :close, :pgroup => true})
    begin
      Timeout.timeout(timeout) do
        Process.waitpid(pid, 0)
        $?.exitstatus == 0
      end
    rescue Timeout::Error
      Process.kill(15, -Process.getpgid(pid))
      puts "Killed pid: #{pid}"
      false
    end
  end

  def tick
    # Determine how many current calls I have according to FreeSWITCH
    fs_calls = %x[fs_cli -x "show calls count"| grep -Po '^\\d+'].to_i

    # Determine how many current channels I have according to FreeSWITCH
    fs_channels = %x[fs_cli -x "show channels count"| grep -Po '^\\d+'].to_i

    # Determine how many conferences I have according to FreeSWITCH
    fs_conferences = %x[fs_cli -x "conference list"| grep -Pco '^Conference'].to_i

    # Try to read pidfile. If it fails use Devil's dummy PID
    begin
      fs_pid = File.read(opts[:pid_file]).to_i
    rescue
      puts "Couldn't read pidfile: #{opts[:pid_file]}"
      fs_pid = -666
    end

    fs_threads = fs_pid > 0 ? %x[ps huH p #{fs_pid} | wc -l].to_i : 0

    # Submit calls to riemann
    if fs_calls > @limits[:calls][:critical]
      alert "FreeSWITCH current calls", :critical, fs_calls, "Number of calls are #{fs_calls}"
    elsif fs_calls > @limits[:calls][:warning]
      alert "FreeSWITCH current calls", :warning, fs_calls, "Number of calls are #{fs_calls}"
    else
      alert "FreeSWITCH current calls", :ok, fs_calls, "Number of calls are #{fs_calls}"
    end

    # Submit channels to riemann
    if fs_channels > @limits[:calls][:critical]
      alert "FreeSWITCH current channels", :critical, fs_channels, "Number of channels are #{fs_channels}"
    elsif fs_channels > @limits[:calls][:warning]
      alert "FreeSWITCH current channels", :warning, fs_channels, "Number of channels are #{fs_channels}"
    else
      alert "FreeSWITCH current channels", :ok, fs_channels, "Number of channels are #{fs_channels}"
    end

    # Submit conferences to riemann
    if fs_conferences > @limits[:calls][:critical]
      alert "FreeSWITCH current conferences", :critical, fs_conferences, "Number of conferences are #{fs_conferences}"
    elsif fs_conferences > @limits[:calls][:warning]
      alert "FreeSWITCH current conferences", :warning, fs_conferences, "Number of conferences are #{fs_conferences}"
    else
      alert "FreeSWITCH current conferences", :ok, fs_conferences, "Number of conferences are #{fs_conferences}"
    end

    # Submit threads to riemann
    if fs_threads
      alert "FreeSWITCH current threads", :ok, fs_threads, "Number of threads are #{fs_threads}"
    end

    # Submit status to riemann
    if dead_proc?(fs_pid)
      alert "FreeSWITCH status", :critical, -1, "FreeSWITCH service status: not running"
    else
      alert "FreeSWITCH status", :ok, nil, "FreeSWITCH service status: running"
    end

    # Submit CLI status to riemann using timeout in case it's unresponsive
    if exec_with_timeout("fs_cli -x status", 2)
      alert "FreeSWITCH CLI status", :ok, nil, "FreeSWITCH CLI status: responsive"
    else
      alert "FreeSWITCH CLI status", :critical, -1, "FreeSWITCH CLI status: not responding"
    end

  end
end

Riemann::Tools::FreeSWITCH.run
