lib/sensu-dashboard/app.rb in sensu-dashboard-0.9.4 vs lib/sensu-dashboard/app.rb in sensu-dashboard-0.9.6.beta
- old
+ new
@@ -1,448 +1,464 @@
-require 'eventmachine'
-require 'sinatra/async'
+require 'sensu/config'
require 'em-http-request'
require 'em-websocket'
+require 'sinatra/async'
require 'sass'
-require 'json'
-require 'sensu/config'
-options = Sensu::Config.read_arguments(ARGV)
-config = Sensu::Config.new(options)
-SETTINGS = config.settings
+class Dashboard < Sinatra::Base
+ register Sinatra::Async
-EventMachine.run do
+ def self.run(options={})
+ EM::run do
+ self.setup(options)
+ self.websocket_server
+ self.run!(:port => $settings.dashboard.port)
- class DashboardServer < Sinatra::Base
-
- register Sinatra::Async
- set :root, File.dirname(__FILE__)
- set :static, true
- set :public_folder, Proc.new { File.join(root, "public") }
-
- api_server = 'http://' + SETTINGS['api']['host'] + ':' + SETTINGS['api']['port'].to_s
-
- use Rack::Auth::Basic do |user, password|
- user == SETTINGS['dashboard']['user'] && password == SETTINGS['dashboard']['password']
+ %w[INT TERM].each do |signal|
+ Signal.trap(signal) do
+ self.stop(signal)
+ end
+ end
end
+ end
- before do
- content_type 'application/json'
+ def self.setup(options={})
+ config = Sensu::Config.new(options)
+ $settings = config.settings
+ $logger = config.logger || config.open_log
+ unless $settings.key?('dashboard')
+ raise config.invalid_config('missing the following key: dashboard')
end
-
- aget '/' do
- content_type 'text/html'
- @js = erb :event_templates, :layout => false
- body erb :index
+ unless $settings.dashboard.port.is_a?(Integer)
+ raise config.invalid_config('dashboard must have a port')
end
-
- aget '/clients' do
- content_type 'text/html'
- @js = erb :client_templates, :layout => false
- body erb :clients
+ unless $settings.dashboard.user.is_a?(String) && $settings.dashboard.password.is_a?(String)
+ raise config.invalid_config('dashboard must have a user and password')
end
-
- aget '/stashes' do
- content_type 'text/html'
- @js = erb :stash_templates, :layout => false
- body erb :stashes
+ if options[:daemonize]
+ Process.daemonize
end
-
- aget '/css/sonian.css' do
- content_type 'text/css'
- body sass :sonian
+ if options[:pid_file]
+ Process.write_pid(options[:pid_file])
end
+ $api_server = 'http://' + $settings.api.host + ':' + $settings.api.port.to_s
+ end
- # api proxy
- aget '/events.json' do
- begin
- http = EventMachine::HttpRequest.new("#{api_server}/events").get
- rescue => e
- puts e
- status 404
- body '{"error":"could not retrieve events from the sensu api"}'
+ def self.websocket_server
+ $websocket_connections = []
+ EM::WebSocket.start(:host => '0.0.0.0', :port => 9000) do |websocket|
+ websocket.onopen do
+ $logger.info('[websocket] -- client connected to websocket')
+ $websocket_connections.push(websocket)
end
-
- http.errback do
- status 404
- body '{"error":"could not retrieve events from the sensu api"}'
+ websocket.onclose do
+ $logger.info('[websocket] -- client disconnected from websocket')
+ $websocket_connections.delete(websocket)
end
+ end
+ end
- http.callback do
- status http.response_header.status
- body http.response
+ set :root, File.dirname(__FILE__)
+ set :static, true
+ set :public_folder, Proc.new { File.join(root, 'public') }
+
+ use Rack::Auth::Basic do |user, password|
+ user == $settings.dashboard.user && password == $settings.dashboard.password
+ end
+
+ before do
+ content_type 'application/json'
+ end
+
+ aget '/' do
+ content_type 'text/html'
+ @js = erb :event_templates, :layout => false
+ body erb :index
+ end
+
+ aget '/clients' do
+ content_type 'text/html'
+ @js = erb :client_templates, :layout => false
+ body erb :clients
+ end
+
+ aget '/stashes' do
+ content_type 'text/html'
+ @js = erb :stash_templates, :layout => false
+ body erb :stashes
+ end
+
+ aget '/css/sonian.css' do
+ content_type 'text/css'
+ body sass :sonian
+ end
+
+ apost '/events.json' do
+ $logger.debug('[events] -- ' + request.ip + ' -- POST -- triggering dashboard refresh')
+ unless $websocket_connections.empty?
+ $websocket_connections.each do |websocket|
+ websocket.send '{"update":"true"}'
end
end
+ body '{"success":"triggered dashboard refresh"}'
+ end
- # api proxy
- aget '/autocomplete.json' do
- multi = EventMachine::MultiRequest.new
+ aget '/autocomplete.json' do
+ multi = EM::MultiRequest.new
- requests = [
- "#{api_server}/events",
- "#{api_server}/clients"
- ]
+ requests = [
+ $api_server + '/events',
+ $api_server + '/clients'
+ ]
- requests.each do |url|
- multi.add EventMachine::HttpRequest.new(url).get
- end
+ requests.each do |url|
+ multi.add EM::HttpRequest.new(url).get
+ end
- multi.callback do
- events = {}
- clients = []
+ multi.callback do
+ events = {}
+ clients = []
- multi.responses[:succeeded].each do |request|
- body = JSON.parse(request.response)
- case body
- when Hash
- events = body
- when Array
- clients = body
- end
+ multi.responses[:succeeded].each do |request|
+ body = JSON.parse(request.response)
+ case body
+ when Hash
+ events = body
+ when Array
+ clients = body
end
+ end
- if events && clients
- autocomplete = []
- statuses = {:warning => [], :critical => [], :unknown => []}
- subscriptions = {}
- checks = []
+ if events && clients
+ autocomplete = []
+ statuses = {:warning => [], :critical => [], :unknown => []}
+ subscriptions = {}
+ checks = []
- # searching by client
- clients.each do |client|
- client_name = client['name']
- if events.include?(client_name)
- autocomplete.push({:value => [client_name], :type => 'client', :name => client_name})
- client['subscriptions'].each do |subscription|
- subscriptions[subscription] ||= []
- subscriptions[subscription].push(client_name)
+ # searching by client
+ clients.each do |client|
+ client_name = client['name']
+ if events.include?(client_name)
+ autocomplete.push({:value => [client_name], :type => 'client', :name => client_name})
+ client['subscriptions'].each do |subscription|
+ subscriptions[subscription] ||= []
+ subscriptions[subscription].push(client_name)
+ end
+ events[client_name].each do |check, event|
+ case event['status']
+ when 1
+ statuses[:warning].push(event['status'])
+ when 2
+ statuses[:critical].push(event['status'])
+ else
+ statuses[:unknown].push(event['status'])
end
- events[client_name].each do |check, event|
-
- case event['status']
- when 1
- statuses[:warning].push(event['status'])
- when 2
- statuses[:critical].push(event['status'])
- else
- statuses[:unknown].push(event['status'])
- end
- checks.push(check)
- end
+ checks.push(check)
end
end
+ end
- # searching by subscription
- subscriptions.each do |k, v|
- autocomplete.push({:value => v.uniq, :type => 'subscription', :name => k})
- end
+ # searching by subscription
+ subscriptions.each do |k, v|
+ autocomplete.push({:value => v.uniq, :type => 'subscription', :name => k})
+ end
- # searching by status
- statuses.each do |k, v|
- autocomplete.push({:value => v.uniq, :type => 'status', :name => k})
- end
+ # searching by status
+ statuses.each do |k, v|
+ autocomplete.push({:value => v.uniq, :type => 'status', :name => k})
+ end
- # searching by check
- checks.uniq.each do |v|
- autocomplete.push({:value => [v], :type => 'check', :name => v})
- end
-
- body autocomplete.to_json
- else
- status 404
- body '{"error":"could not retrieve events and/or clients from the sensu api"}'
+ # searching by check
+ checks.uniq.each do |v|
+ autocomplete.push({:value => [v], :type => 'check', :name => v})
end
- end
- end
- aget '/clients.json' do
- begin
- http = EventMachine::HttpRequest.new("#{api_server}/clients").get
- rescue => e
- puts e
+ body autocomplete.to_json
+ else
status 404
- body '{"error":"could not retrieve clients from the sensu api"}'
+ body '{"error":"could not retrieve events and/or clients from the sensu api"}'
end
+ end
+ end
- http.errback do
- status 404
- body '{"error":"could not retrieve clients from the sensu api"}'
- end
+ aget '/clients/autocomplete.json' do
+ multi = EM::MultiRequest.new
- http.callback do
- status http.response_header.status
- body http.response
- end
+ requests = [
+ $api_server + '/clients'
+ ]
+
+ requests.each do |url|
+ multi.add EM::HttpRequest.new(url).get
end
- # api proxy
- aget '/clients/autocomplete.json' do
- multi = EventMachine::MultiRequest.new
+ multi.callback do
+ events = {}
+ clients = []
- requests = [
- "#{api_server}/clients"
- ]
-
- requests.each do |url|
- multi.add EventMachine::HttpRequest.new(url).get
+ multi.responses[:succeeded].each do |request|
+ body = JSON.parse(request.response)
+ case body
+ when Array
+ clients = body
+ end
end
- multi.callback do
- events = {}
- clients = []
+ if clients
+ autocomplete = []
+ subscriptions = {}
- multi.responses[:succeeded].each do |request|
- body = JSON.parse(request.response)
- case body
- when Array
- clients = body
+ # searching by client
+ clients.each do |client|
+ client_name = client['name']
+ autocomplete.push({:value => [client_name], :type => 'client', :name => client_name})
+ client['subscriptions'].each do |subscription|
+ subscriptions[subscription] ||= []
+ subscriptions[subscription].push(client_name)
end
end
- if clients
- autocomplete = []
- subscriptions = {}
-
- # searching by client
- clients.each do |client|
- client_name = client['name']
- autocomplete.push({:value => [client_name], :type => 'client', :name => client_name})
- client['subscriptions'].each do |subscription|
- subscriptions[subscription] ||= []
- subscriptions[subscription].push(client_name)
- end
- end
-
- # searching by subscription
- subscriptions.each do |k, v|
- autocomplete.push({:value => v.uniq, :type => 'subscription', :name => k})
- end
-
- body autocomplete.to_json
- else
- status 404
- body '{"error":"could not retrieve clients from the sensu api"}'
+ # searching by subscription
+ subscriptions.each do |k, v|
+ autocomplete.push({:value => v.uniq, :type => 'subscription', :name => k})
end
- end
- end
- aget '/client/:id.json' do |id|
- begin
- http = EventMachine::HttpRequest.new("#{api_server}/client/#{id}").get
- rescue => e
- puts e
+ body autocomplete.to_json
+ else
status 404
- body '{"error":"could not retrieve client from the sensu api"}'
+ body '{"error":"could not retrieve clients from the sensu api"}'
end
+ end
+ end
- http.errback do
- status 404
- body '{"error":"could not retrieve client from the sensu api"}'
- end
+ #
+ # API Proxy
+ #
- http.callback do
- status http.response_header.status
- body http.response
- end
+ aget '/events.json' do
+ begin
+ http = EM::HttpRequest.new($api_server + '/events').get
+ rescue => e
+ $logger.warning(e)
+ status 404
+ body '{"error":"could not retrieve events from the sensu api"}'
end
- adelete '/client/:id.json' do |id|
- begin
- http = EventMachine::HttpRequest.new("#{api_server}/client/#{id}").delete
- rescue => e
- puts e
- status 404
- body '{"error":"could not delete client from the sensu api"}'
- end
+ http.errback do
+ status 404
+ body '{"error":"could not retrieve events from the sensu api"}'
+ end
- http.errback do
- status 404
- body '{"error":"could not delete client from the sensu api"}'
- end
+ http.callback do
+ status http.response_header.status
+ body http.response
+ end
+ end
- http.callback do
- status http.response_header.status
- body http.response
- end
+ aget '/clients.json' do
+ begin
+ http = EM::HttpRequest.new($api_server + '/clients').get
+ rescue => e
+ $logger.warning(e)
+ status 404
+ body '{"error":"could not retrieve clients from the sensu api"}'
end
- aget '/stash/*.json' do |path|
- begin
- http = EventMachine::HttpRequest.new("#{api_server}/stash/#{path}").get
- rescue => e
- puts e
- status 404
- body '{"error":"could not retrieve a stash from the sensu api"}'
- end
+ http.errback do
+ status 404
+ body '{"error":"could not retrieve clients from the sensu api"}'
+ end
- http.errback do
- status 404
- body '{"error":"could not retrieve a stash from the sensu api"}'
- end
+ http.callback do
+ status http.response_header.status
+ body http.response
+ end
+ end
- http.callback do
- status http.response_header.status
- body http.response
- end
+ aget '/client/:id.json' do |id|
+ begin
+ http = EM::HttpRequest.new($api_server + '/client/' + id).get
+ rescue => e
+ $logger.warning(e)
+ status 404
+ body '{"error":"could not retrieve client from the sensu api"}'
end
- apost '/stash/*.json' do |path|
- begin
- request_options = {
- :body => {'timestamp' => Time.now.to_i}.to_json,
- :head => {
- 'content-type' => 'application/json'
- }
- }
- http = EventMachine::HttpRequest.new("#{api_server}/stash/#{path}").post request_options
- rescue => e
- puts e
- status 404
- body '{"error":"could not create a stash with the sensu api"}'
- end
+ http.errback do
+ status 404
+ body '{"error":"could not retrieve client from the sensu api"}'
+ end
- http.errback do
- status 404
- body '{"error":"could not create a stash with the sensu api"}'
- end
+ http.callback do
+ status http.response_header.status
+ body http.response
+ end
+ end
- http.callback do
- status http.response_header.status
- body http.response
- end
+ adelete '/client/:id.json' do |id|
+ begin
+ http = EventMachine::HttpRequest.new($api_server + '/client/' + id).delete
+ rescue => e
+ $logger.warning(e)
+ status 404
+ body '{"error":"could not delete client from the sensu api"}'
end
- adelete '/stash/*.json' do |path|
- begin
- http = EventMachine::HttpRequest.new("#{api_server}/stash/#{path}").delete
- rescue => e
- puts e
- status 404
- body '{"error":"could not delete a stash with the sensu api"}'
- end
+ http.errback do
+ status 404
+ body '{"error":"could not delete client from the sensu api"}'
+ end
- http.errback do
- status 404
- body '{"error":"could not delete a stash with the sensu api"}'
- end
+ http.callback do
+ status http.response_header.status
+ body http.response
+ end
+ end
- http.callback do
- status http.response_header.status
- body http.response
- end
+ aget '/stash/*.json' do |path|
+ begin
+ http = EM::HttpRequest.new($api_server + '/stash/' + path).get
+ rescue => e
+ $logger.warning(e)
+ status 404
+ body '{"error":"could not retrieve a stash from the sensu api"}'
end
- apost '/event/resolve.json' do
- begin
- request_options = {
- :body => request.body.read,
- :head => {
- 'content-type' => 'application/json'
- }
+ http.errback do
+ status 404
+ body '{"error":"could not retrieve a stash from the sensu api"}'
+ end
+
+ http.callback do
+ status http.response_header.status
+ body http.response
+ end
+ end
+
+ apost '/stash/*.json' do |path|
+ begin
+ request_options = {
+ :body => {'timestamp' => Time.now.to_i}.to_json,
+ :head => {
+ 'content-type' => 'application/json'
}
- http = EventMachine::HttpRequest.new("#{api_server}/event/resolve").post request_options
- rescue => e
- puts e
- status 404
- body '{"error":"could not resolve an event with the sensu api"}'
- end
+ }
+ http = EM::HttpRequest.new($api_server + '/stash/' + path).post request_options
+ rescue => e
+ $logger.warning(e)
+ status 404
+ body '{"error":"could not create a stash with the sensu api"}'
+ end
- http.errback do
- status 404
- body '{"error":"could not resolve an event with the sensu api"}'
- end
+ http.errback do
+ status 404
+ body '{"error":"could not create a stash with the sensu api"}'
+ end
- http.callback do
- status http.response_header.status
- body http.response
- end
+ http.callback do
+ status http.response_header.status
+ body http.response
end
+ end
- aget '/stashes.json' do
- begin
- request_options = {
-# :body => request.body.read,
- :head => {
- 'content-type' => 'application/json'
- }
- }
- http = EventMachine::HttpRequest.new("#{api_server}/stashes").get request_options
- rescue => e
- puts e
- status 404
- body '{"error":"could not retrieve a list of stashes from the sensu api"}'
- end
+ adelete '/stash/*.json' do |path|
+ begin
+ http = EM::HttpRequest.new($api_server + '/stash/' + path).delete
+ rescue => e
+ $logger.warning(e)
+ status 404
+ body '{"error":"could not delete a stash with the sensu api"}'
+ end
- http.errback do
- status 404
- body '{"error":"could not retrieve a list of stashes from the sensu api"}'
- end
+ http.errback do
+ status 404
+ body '{"error":"could not delete a stash with the sensu api"}'
+ end
- http.callback do
- resp = http.response
- status http.response_header.status
- body resp
- end
+ http.callback do
+ status http.response_header.status
+ body http.response
end
+ end
- apost '/stashes.json' do
- begin
- request_options = {
- :body => request.body.read,
- :head => {
- 'content-type' => 'application/json'
- }
+ apost '/event/resolve.json' do
+ begin
+ request_options = {
+ :body => request.body.read,
+ :head => {
+ 'content-type' => 'application/json'
}
- http = EventMachine::HttpRequest.new("#{api_server}/stashes").post request_options
- rescue => e
- puts e
- status 404
- body '{\"error\":\"could not retrieve a list of stashes from the sensu api\"}'
- end
+ }
+ http = EM::HttpRequest.new($api_server + '/event/resolve').post request_options
+ rescue => e
+ $logger.warning(e)
+ status 404
+ body '{"error":"could not resolve an event with the sensu api"}'
+ end
- http.errback do
- status 404
- body '{\"error\":\"could not retrieve a list of stashes from the sensu api\"}'
- end
+ http.errback do
+ status 404
+ body '{"error":"could not resolve an event with the sensu api"}'
+ end
- http.callback do
- resp = http.response
- puts resp
- status http.response_header.status
- body resp
- end
+ http.callback do
+ status http.response_header.status
+ body http.response
end
+ end
- websocket_connections = Array.new
- EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 9000) do |websocket|
- websocket.onopen do
- websocket_connections.push websocket
- puts 'client connected to websocket'
- end
- websocket.onclose do
- websocket_connections.delete websocket
- puts 'client disconnected from websocket'
- end
+ aget '/stashes.json' do
+ begin
+ http = EM::HttpRequest.new($api_server + '/stashes').get
+ rescue => e
+ $logger.warning(e)
+ status 404
+ body '{"error":"could not retrieve a list of stashes from the sensu api"}'
end
- apost '/events.json' do
- unless websocket_connections.empty?
- websocket_connections.each do |websocket|
- websocket.send '{"update":"true"}'
- end
- end
- body '{"success":"triggered dashboard refresh"}'
+ http.errback do
+ status 404
+ body '{"error":"could not retrieve a list of stashes from the sensu api"}'
end
+
+ http.callback do
+ status http.response_header.status
+ body http.response
+ end
end
- DashboardServer.run!({:port => SETTINGS['dashboard']['port']})
+ apost '/stashes.json' do
+ begin
+ request_options = {
+ :body => request.body.read,
+ :head => {
+ 'content-type' => 'application/json'
+ }
+ }
+ http = EM::HttpRequest.new($api_server + '/stashes').post request_options
+ rescue => e
+ $logger.warning(e)
+ status 404
+ body '{"error":"could not retrieve a list of stashes from the sensu api"}'
+ end
- #
- # Recognize exit command
- #
- Signal.trap("INT") do
- EM.stop
+ http.errback do
+ status 404
+ body '{"error":"could not retrieve a list of stashes from the sensu api"}'
+ end
+
+ http.callback do
+ status http.response_header.status
+ body http.response
+ end
end
- Signal.trap("TERM") do
- EM.stop
- end
+ def self.stop(signal)
+ $logger.warn('[stop] -- stopping sensu dashboard -- ' + signal)
+ EM::Timer.new(1) do
+ EM::stop_event_loop
+ end
+ end
end
+
+options = Sensu::Config.read_arguments(ARGV)
+Dashboard.run(options)