%w{ mixlib/cli mixlib/log json thin eventmachine em-websocket directory_watcher nagios_analyzer sinatra/async haml spice }.each do |gem| require gem end class Options include Mixlib::CLI option :verbose, :short => '-v', :long => '--verbose', :boolean => true, :default => false, :description => 'Output debug messages to screen' option :datfile, :short => '-d FILE', :long => '--datfile FILE', :default => '/var/cache/nagios3/status.dat', :description => 'Location of Nagios status.dat FILE' option :port, :short => '-p PORT', :long => '--port PORT', :default => 80, :description => 'Listen on a different PORT' option :logfile, :short => '-l FILE', :long => '--logfile FILE', :default => '/tmp/nagios-dashboard.log', :description => 'Log to a different FILE' option :chef, :short => '-c SERVER', :long => '--chef SERVER', :description => 'Use a Chef SERVER' option :user, :short => '-u USER', :long => '--user USER', :description => 'Chef USER name' option :key, :short => '-k KEY', :long => '--key KEY', :default => '/etc/chef/client.pem', :description => 'Chef user KEY' option :organization, :short => '-o ORGANIZATION', :long => '--organization ORGANIZATION', :description => 'Use a OpsCode platform ORGANIZATION' option :help, :short => "-h", :long => "--help", :description => "Show this message", :on => :tail, :boolean => true, :show_options => true, :exit => 0 end class Log extend Mixlib::Log end OPTIONS = Options.new OPTIONS.parse_options Log.init(OPTIONS.config[:logfile]) Log.debug('starting dashboard ...') EventMachine.epoll if EventMachine.epoll? EventMachine.kqueue if EventMachine.kqueue? EventMachine.run do class Dashboard < Sinatra::Base register Sinatra::Async set :root, File.dirname(__FILE__) set :static, true set :public, Proc.new { File.join(root, "static") } Spice.setup do |s| s.host = OPTIONS.config[:chef] || "api.opscode.com" s.port = 443 s.scheme = "https" s.url_path = '/organizations/' + OPTIONS.config[:organization] if OPTIONS.config[:chef].nil? s.client_name = OPTIONS.config[:user] s.key_file = OPTIONS.config[:key] end Spice.connect! aget '/' do EventMachine.defer(proc { haml :dashboard }, proc { |result| body result }) end aget '/node/:hostname' do |hostname| content_type 'application/json' EventMachine.defer(proc { JSON.parse(Spice::Search.node('hostname:' + hostname))['rows'][0] }, proc { |result| body result.to_json }) end end def log_message(message) if OPTIONS.config[:verbose] puts message end EventMachine.defer(proc { Log.debug(message) }) end websocket_connections = Array.new EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 8000) do |websocket| websocket.onopen do websocket_connections.push websocket log_message('client connected to websocket') end websocket.onclose do websocket_connections.delete websocket log_message('client disconnected from websocket') end end nagios_status = proc do begin nagios = NagiosAnalyzer::Status.new(OPTIONS.config[:datfile]) nagios.items.to_json rescue => error log_message(error) end end update_clients = proc do |nagios| unless nagios.nil? websocket_connections.each do |websocket| websocket.send nagios end log_message('updated clients') end end watcher = DirectoryWatcher.new File.dirname(File.expand_path(OPTIONS.config[:datfile])), :glob => '*.dat', :scanner => :em watcher.add_observer do |*args| args.each do |event| unless websocket_connections.count == 0 EventMachine.defer(nagios_status, update_clients) end end end watcher.start Dashboard.run!({:port => OPTIONS.config[:port]}) end Log.debug('stopping dashboard ...')