These are notes and code snippets for setting up a "personal dashboard". The impetus for this was that I wanted a way to visually monitor ad-hoc things on our servers. If they prove to be useful monitors then the idea is that they get moved into grafana, kibana, etc. where everyone can share them.
Sometimes you just want to run a command on a bunch of servers and graph/display the output in a nice way. :)
knife ssh
can be handy for this if you're using chef, but I wanted something with even less overhead/setup.
This POC uses dashing and ansible only so the requirements are:
- install dashing (modern ruby, bundler, some gems)
- install ansible (pip or provided OS package) and have ssh access to the servers
Since this is a POC I'm not going to detail how to set this up completely just yet. Here's the basic idea though using an uptime display as an example (and some code snippets):
After installing dashing and ansible I setup a job for uptime. It looks something like this:
require 'json'
require 'pp'
groups = %w(foo bar baz)
job = 'uptime'
inventory_file = '/path/to/inventory' # ansible formatted inventory file
SCHEDULER.every '600s' do
# run ansible to generate uptime data for all groups
groups.each do |group|
output_dir = "/path/to/ansible_output/#{job}-#{group}"
command = "ansible -t #{output_dir} -i #{inventory_file} #{group} -m shell -a 'uptime' --sudo"
system(command)
# parse output of files into appropriate structure
hosts = Dir.glob(File.join(output_dir, '*'))
uptimes = Hash.new({ value: '?'}) # default value indicates unknown uptime
hosts.each do |h|
hostname = File.basename(h).gsub('.some.domain.to.remove', '')
contents = JSON.parse(File.open(h, 'r').read)
uptime = contents['stdout'].match(/up(.*?),\s+\d+ user/)[1]
# check date
age = uptime.match(/(\d+) days/)
if age && age[1].to_i > 30
color = '#BD4932'
else
color = 'rgba(255, 255, 255, 0.7)'
end
uptimes[h] = { label: hostname, value: uptime, style: { color: color} }
end
send_event(group, { items: uptimes.values })
end
end
As part of dashing the above job runs automatically and executes the ansible commmand every 5 minutes. The resulting JSON output is parsed and cleaned up a bit, then sent to the dashboard view (in the usual dashing way).
The next piece is a dashboard display. Something like this:
<% content_for :title do %>System Uptimes<% end %>
<div class="gridster">
<ul>
<li data-row="1" data-col="1" data-sizex="1" data-sizey="1">
<div style="background-color: #96bf48;" data-id="foo" data-view="List" data-unordered="true" data-title="FOO"></div>
</li>
<li data-row="1" data-col="2" data-sizex="1" data-sizey="1">
<div style="background-color: #ff9618;"data-id="bar" data-view="List" data-unordered="true" data-title="BAR"></div>
</li>
<li data-row="1" data-col="3" data-sizex="1" data-sizey="1">
<div style="background-color: #47bbb3;" data-id="baz" data-view="List" data-unordered="true" data-title="BAZ"></div>
</li>
</ul>
</div>
After that it's just a matter of firing up dashing and hitting the instance with a browser to see the data.
I should note that the inventory file is a standard ansible inventory file with servers listed by group (foo bar baz).
I'm going to continue playing with this locally and trying out different use-cases I had in mind (and using some of the other dashing widgets available).
My hope is to arrive at a reusable framework where ansible commands, hosts, and dashboard can be quickly and easily defined (possibly by just coping an existing similar example). If that day comes I'll move this into a separate repo and type some proper setup instructions. :)