Skip to content

Instantly share code, notes, and snippets.

@MWilkinson
Last active July 5, 2022 12:37
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MWilkinson/a99df410ed9060724b24 to your computer and use it in GitHub Desktop.
Save MWilkinson/a99df410ed9060724b24 to your computer and use it in GitHub Desktop.
Dashing Dashboard Widget - Icinga Hosts/Services Status Summary

##Preview

See images below

Description

Simple Dashing widget (and associated job) to query an Icinga monitoring system and display the hosts and services status summary

Widget background colour is changes on the following priority :- Default is OK - background is green. For host state unknown or service state warning - background is Yellow. For host state down or service state critical - background is Red.

The highest state overrides lower state settings, i.e., with a warning state and a critical state, the critical state wins and the background will be coloured red.

##Usage

To use this widget, copy icinga.html, icinga.coffee, and icinga.scss into the /widgets/icinga directory. Put the icinga.rb file in your /jobs folder. Copy the icinga.yml into the root of your dashing application.

Alternatively install using the following command, then create your own icinga.yml configuration file

dashing install a99df410ed9060724b24

To include the widget in a dashboard, add the following snippets to the dashboard layout file:

<li data-row="1" data-col="1" data-sizex="1" data-sizey="1">
  <div data-id="icinga_host_status" data-view="Icinga" data-title="Host Status"></div>
</li>

<li data-row="1" data-col="2" data-sizex="1" data-sizey="1">
  <div data-id="icinga_service_status" data-view="Icinga" data-title="Service Status"></div>
</li>

##Settings

You'll need to configure the icinga.yml file with the base uri of your icinga server. I.e. https://icinga.myhost.com/ Add the authorisation key to use when accessing the api - this can be set in the icinga control panel. If you want, change the refresh rate.

class Dashing.Icinga extends Dashing.Widget
ready: ->
onData: (data) ->
node = $(@node)
node.removeClass('icinga-warning')
node.removeClass('icinga-critical')
node.addClass('icinga-ok')
if data.services
if data.services.WARNING.value
console.log('services Warning')
node.removeClass('icinga-ok')
node.removeClass('icinga-critical')
node.addClass('icinga-warning')
if data.services.CRITICAL.value
console.log('services Critial')
node.removeClass('icinga-ok')
node.removeClass('icinga-warning')
node.addClass('icinga-critical')
if data.hosts
if data.hosts.UNREACHABLE.value
node.removeClass('icinga-ok')
node.removeClass('icinga-critical')
node.addClass('icinga-warning')
if data.hosts.DOWN.value
node.removeClass('icinga-ok')
node.removeClass('icinga-warning')
node.addClass('icinga-critical')
<h1 class="title" data-bind="title"></h1>
<ul class="list-nostyle">
<li data-showif='services'>
<span class="label" data-bind="services.OK.label"></span>
<span class="value" data-bind="services.OK.value"></span>
</li>
<li data-showif='services'>
<span class="label" data-bind="services.WARNING.label"></span>
<span class="value" data-bind="services.WARNING.value"></span>
</li>
<li data-showif='services'>
<span class="label" data-bind="services.CRITICAL.label"></span>
<span class="value" data-bind="services.CRITICAL.value"></span>
</li>
<li data-showif='services'>
<span class="label" data-bind="services.UNKNOWN.label"></span>
<span class="value" data-bind="services.UNKNOWN.value"></span>
</li>
<li data-showif='services'>
<span class="label" data-bind="services.Total.label"></span>
<span class="value" data-bind="services.Total.value"></span>
</li>
<li data-showif='hosts'>
<span class="label" data-bind="hosts.UP.label"></span>
<span class="value" data-bind="hosts.UP.value"></span>
</li>
<li data-showif='hosts'>
<span class="label" data-bind="hosts.DOWN.label"></span>
<span class="value" data-bind="hosts.DOWN.value"></span>
</li>
<li data-showif='hosts'>
<span class="label" data-bind="hosts.PENDING.label"></span>
<span class="value" data-bind="hosts.PENDING.value"></span>
</li>
<li data-showif='hosts'>
<span class="label" data-bind="hosts.UNREACHABLE.label"></span>
<span class="value" data-bind="hosts.UNREACHABLE.value"></span>
</li>
<li data-showif='hosts'>
<span class="label" data-bind="hosts.Total.label"></span>
<span class="value" data-bind="hosts.Total.value"></span>
</li>
</ul>
<p class="more-info" data-bind="moreinfo"></p>
<p class="updated-at" data-bind="updatedAtMessage"></p>
require 'addressable/uri'
require 'net/http'
require 'json'
#
# Hard coded configuration variables - should not be updated unless you know what you are doing
#
yamlFile = "./icinga.yml"
serviceStateMap = %w(OK WARNING CRITICAL UNKNOWN)
hostStateMap = %w(UP DOWN UNREACHABLE PENDING)
if File.exist?(yamlFile)
config = YAML.load(File.new(yamlFile, "r").read)
configuration = config[:icinga]
else
configuration = {
:base_uri => '',
:authkey => '',
:refresh_rate => '30s',
}
end
class IcingaRequest
attr_accessor :host,
:authkey,
:target,
:filter,
:columns,
:column_count,
:order,
:output
def initialize(params)
@host = params[:host]
@target = params[:target]
@filter = params[:filter]
@columns = params[:columns]
@column_count = params[:column_count]
@order = params[:order]
@authkey = params[:authkey]
@output = params[:output]
end
def get
uri = Addressable::URI.parse to_url
#
# For some reason, addressable does not set the port to 443 by default for https:// urls
# Work around that here - add a catchall for http and https
#
if uri.port.nil?
if uri.scheme == 'https'
uri.port = 443
elsif uri.scheme == 'http'
uri.port = 80
end
end
req = Net::HTTP.new(uri.host, uri.port)
if uri.scheme == 'https'
req.use_ssl = true
end
res = req.get(uri.request_uri)
res.code == '200' ? res.body : ''
end
#
# Build the URL to access Icinga with
#
def to_url
"%s/web/api/%s/%s/authkey=%s/%s" % [ host, target, url_options, authkey, output ]
end
#
# Build the optional part of the URL
#
def url_options
[ filter_url, columns_url, order_url, column_count_url].compact.join('/')
end
def filter_url
self.filter ? "filter[%s]" % filter : nil
end
def columns_url
self.columns ? "columns[%s]" % columns.join('|') : nil
end
def order_url
self.order ? "order(%s)" % order.join('|') : nil
end
def column_count_url
self.column_count ? "countColumn=%s" % count_column : nil
end
end
def count_summary(req, stateMap)
objs = JSON.load(req.get)
states = Hash.new( :value => 0 )
stateMap.each do |state|
states[state] = { label: state, value: 0 }
end
objs['result'].each do |res|
lState = stateMap[ res['SERVICE_CURRENT_STATE'].to_i ]
states[ lState ] = { label: lState, value: (states[lState][:value] + 1) }
end
err = 0
tot = 0
stateMap.each do |state|
if state != 'OK' and state != 'UP'
err = err + states[state][:value]
end
tot = tot + states[state][:value]
end
states['Total'] = { label: 'Total', value: "%d / %d" % [ err, tot ] }
return states
end
SCHEDULER.every configuration[:refresh_rate] do
serviceReq = IcingaRequest.new(
:host => configuration[:base_uri],
:target => 'service',
:authkey => configuration[:authkey],
:columns => ['SERVICE_NAME',
'HOST_NAME',
'SERVICE_CURRENT_STATE',
'HOST_CURRENT_STATE',
'SERVICE_ID' ],
:order => [ 'SERVICE_ID;DESC' ],
:count_column => 'SERVICE_ID',
:output => 'json'
)
serviceStates = count_summary(serviceReq, serviceStateMap)
hostReq = IcingaRequest.new(
:host => configuration[:base_uri],
:target => 'host',
:authkey => configuration[:authkey],
:columns => ['HOST_NAME',
'HOST_CURRENT_STATE',
'HOST_ID' ],
:order => [ 'HOST_ID;DESC' ],
:count_column => 'HOST_ID',
:output => 'json'
)
hostStates = count_summary(hostReq, hostStateMap)
send_event( 'icinga_host_status', { hosts: hostStates } )
send_event( 'icinga_service_status', { services: serviceStates } )
end
// ----------------------------------------------------------------------------
// Sass declarations
// ----------------------------------------------------------------------------
$background-color: #12b0c5;
$value-color: #fff;
$background-critical-color: #f00;
$background-warning-color: #ff0;
$background-ok-color: #0f0;
$title-color: rgba(255, 255, 255, 0.7);
$label-color: rgba(255, 255, 255, 0.7);
$moreinfo-color: rgba(255, 255, 255, 0.7);
// ----------------------------------------------------------------------------
// Widget-list styles
// ----------------------------------------------------------------------------
.widget-icinga {
background-color: $background-color;
vertical-align: top;
.title {
color: $title-color;
}
ol, ul {
margin: 0 15px;
text-align: left;
color: $label-color;
}
ol {
list-style-position: inside;
}
li {
margin-bottom: 5px;
}
.list-nostyle {
list-style: none;
}
.critical {
background: red;
}
.warning {
background: yellow;
}
.label {
color: $label-color;
}
.value {
float: right;
margin-left: 12px;
font-weight: 600;
color: $value-color;
}
.updated-at {
color: rgba(0, 0, 0, 0.3);
}
.more-info {
color: $moreinfo-color;
}
&.icinga-warning {
background-color: yellow;
.label, .value, .title {
color: black;
}
}
&.icinga-critical {
background-color: red;
}
&.icinga-ok {
background-color: green;
}
}
---
:icinga:
:base_uri: 'http://<hostname/base uri to /web/api>'
:authkey: '<icinga authkey goes here>'
:refresh_rate: '1m'
@gqs
Copy link

gqs commented Jan 12, 2016

Hello

I have this error :
scheduler caught exception:
undefined method []' for nil:NilClass /usr/home/dashing/dashing-icinga-master/jobs/icinga.rb:105:incount_summary'
/usr/home/dashing/dashing-icinga-master/jobs/icinga.rb:151:in block in <top (required)>' /usr/local/lib/ruby/gems/2.1/gems/rufus-scheduler-2.0.24/lib/rufus/sc/jobs.rb:230:incall'
/usr/local/lib/ruby/gems/2.1/gems/rufus-scheduler-2.0.24/lib/rufus/sc/jobs.rb:230:in trigger_block' /usr/local/lib/ruby/gems/2.1/gems/rufus-scheduler-2.0.24/lib/rufus/sc/jobs.rb:204:inblock in trigger'
/usr/local/lib/ruby/gems/2.1/gems/rufus-scheduler-2.0.24/lib/rufus/sc/scheduler.rb:430:in call' /usr/local/lib/ruby/gems/2.1/gems/rufus-scheduler-2.0.24/lib/rufus/sc/scheduler.rb:430:inblock in trigger_job'

Thanks

@gqs
Copy link

gqs commented Jan 12, 2016

Ok sorry, it's a auth problem. [RESOLVED]

@schoerg
Copy link

schoerg commented Feb 7, 2017

What does the output of serviceStates or hostStates look like?
Edit: nevermind found it.

@RandieM
Copy link

RandieM commented Oct 23, 2018

Hi there. Does this widget work with all Icinga versions? Thanks!

@chaudharivinit
Copy link

Can anyone please let me know how to create auth key for icinga.yml in Icinga2? We have searched every bit of Icinga documentation but did not find anything related to auth key generation. Normally Icinga2 supports API authentication via Uname and password.

@chaudharivinit
Copy link

@MWilkinson Can you please provide us with the new icinga.rb which reads api user credentials from api-users.conf for icinga2?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment