Skip to content
This repository has been archived by the owner on Jun 2, 2020. It is now read-only.

Commit

Permalink
Merge branch 'joerayme-events_view'
Browse files Browse the repository at this point in the history
  • Loading branch information
alex-leonhardt committed Apr 24, 2016
2 parents 14df4a5 + 1bb108a commit 7909c1d
Show file tree
Hide file tree
Showing 8 changed files with 165 additions and 18 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,6 @@ crashlytics-build.properties

# testing
.coverage

# Config
conf/config.yaml
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Flask application to connect to a list of sensu-api servers and displays a grid

- overview by data centre ( Name, OK, WARN, CRIT, DOWN, ACK )
- detail view by data centre ( Grid of hosts, color changes based on amount of alerting checks, 1 = yellow, > 1 = red, down = purple )

- Events view by data centre (Grid of events which are currently alerting/warning/unknown)
- filter by hosts' subscription/s ( Only shows matchin hosts' check results in overview and detail view)

## screenshots
Expand All @@ -19,14 +19,14 @@ Overview (DCs)

# faq

#### how can I filter by more than 1 subscription ?
#### how can I filter by more than 1 value?

Amend the URL and add all the subscriptions together as a comma-separated list, e.g.:
Amend the URL and add all the filters together as a comma-separated list, e.g.:
http://localhost:5000/filtered/aaa,bbb,ccc,ddd

#### what do the filters filter by ?

They filter based on the hosts' subscriptions.
They filter based on the hosts' subscriptions, except in the Events view where they filter on all properties of the check and the host.

# docker

Expand Down Expand Up @@ -102,6 +102,8 @@ Add via pip install or via your package management

## configuration

You should copy the ```conf/config.yaml.sample``` file to ```conf/config.yaml``` and edit as appropriate.

If you use username/password, ensure you set the appropriate permissions - e.g. ```chmod 640 conf/config.yaml``` and set the owner to ```sensu-grid``` which you'll be using to run this app.

### example config
Expand Down
File renamed without changes.
48 changes: 48 additions & 0 deletions griddata.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,54 @@ def get_stashes(dc):
return data


def filter_object(obj, search):
if type(obj) == dict:
for k, value in obj.iteritems():
if filter_object(value, search):
return True
elif type(obj) == list:
for value in obj:
if filter_object(value, search):
return True
else:
return unicode(search) in unicode(obj)

return False


def filter_events(filters):
def filter_event(event):
for f in filters:
if filter_object(event, f):
return True
return False

return filter_event


def get_events(dc, filters=[]):
url = 'http://{0}:{1}/events'.format(dc['url'], dc['port'])

data = []
r = None

try:
if 'user' and 'password' in dc:
r = requests.get(url, auth=(dc['user'], dc['password']))
data = r.json()
else:
r = requests.get(url)
data = r.json()
finally:
if r:
r.close()

if len(filters) > 0:
return filter(filter_events(filters), data)
else:
return data


def agg_data(dc, data, stashes, client_data=None, filters=None):
"""
Aggregates json data and returns count of ok, warn, crit
Expand Down
66 changes: 54 additions & 12 deletions sensugrid.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,43 +39,58 @@ def root():
return render_template('data.html', dcs=dcs, data=aggregated, filter_data=get_filter_data(dcs), appcfg=appcfg)


@app.route('/filtered/<string:subscriptions>', methods=['GET'])
def filtered(subscriptions):
@app.route('/filtered/<string:filters>', methods=['GET'])
def filtered(filters):
aggregated = []
for dc in dcs:
if check_connection(dc):
aggregated.append(agg_data(dc, get_data(dc), get_stashes(dc), get_clients(dc), subscriptions))
aggregated.append(agg_data(dc, get_data(dc), get_stashes(dc), get_clients(dc), filters))

return render_template('data.html', dcs=dcs, data=aggregated, filter_data=get_filter_data(dcs), appcfg=appcfg)


@app.route('/show/<string:d>', methods=['GET'])
def showgrid(d):
@app.route('/show/<string:d>/filtered/<string:filters>', methods=['GET'])
def showgrid(d, filters=None):
data_detail = {}
if dcs:
for dc in dcs:
if dc['name'] == d:
if check_connection(dc):
data_detail = agg_host_data(get_data(dc), get_stashes(dc))
if filters:
clients = get_clients(dc)
else:
clients = None

data_detail = agg_host_data(get_data(dc), get_stashes(dc), clients, filters)
if data_detail:
break
else:
abort(404)
return render_template('detail.html', dc=dc, data=data_detail, filter_data=get_filter_data(dcs), appcfg=appcfg)


@app.route('/show/<string:d>/filtered/<string:subscriptions>', methods=['GET'])
def showgrid_filtered(d, subscriptions):
aggregated = {}
@app.route('/events/<string:d>')
@app.route('/events/<string:d>/filtered/<string:filters>')
def events(d, filters=''):
results = []

dc_found = False

if dcs:
for dc in dcs:
if dc['name'] == d:
dc_found = True
if check_connection(dc):
aggregated = (agg_host_data(get_data(dc), get_stashes(dc), get_clients(dc), subscriptions))
if len(aggregated) > 0:
break
results += get_events(dc, filters.split(','))
break

return render_template('detail.html', dc=dc, data=aggregated, filter_data=get_filter_data(dcs), appcfg=appcfg)
if dc_found is False:
abort(404)

results = sorted(results, lambda x, y: cmp(x['check']['status'], y['check']['status']), reverse=True)

return render_template('events.html', dc=dc, data=results, filter_data=get_filter_data(dcs), appcfg=appcfg)


@app.route('/healthcheck', methods=['GET'])
Expand Down Expand Up @@ -105,6 +120,33 @@ def healthcheck():
return json.dumps(ret)


@app.template_filter('color_for_event')
def color_for_event(event):
if event['check']['name'] == 'keepalive':
return 'purple'
if event['check']['status'] == 1:
return 'yellow'
if event['check']['status'] == 2:
return 'red'
if event['check']['status'] == 0:
return 'green'

return 'gray'


@app.template_filter('icon_for_event')
def icon_for_event(event):
if event['check']['name'] == 'keepalive':
return 'arrow-circle-down'
if event['check']['status'] == 1:
return 'exclamation-circle'
if event['check']['status'] == 2:
return 'times-circle-o'
if event['check']['status'] == 0:
return 'check-circle'

return 'question-circle'

if __name__ == '__main__':

app.run(host='0.0.0.0',
Expand Down
41 changes: 41 additions & 0 deletions templates/events.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{% extends "menu_detail.html" %}
{% block data %}

{% for event in data %}
{% if loop.first or loop.index0 % 3 == 0 %}<div class="row spacer">{% endif %}
<div class="col-xs-4">
<div class="small-box bg-{{ event|color_for_event }} icon-xs">
<div class="inner" style="text-align: center;" title="{{ k }}" data-toggle="tooltip" data-placement="right">
<h1>{{ event.check.name|replace('_', ' ')|replace('-', ' ')|replace('.', ' ') }}</h1>
<div class="icon">
<i class="fa fa-{{ event|icon_for_event }}"></i>
</div>
<p>{{ event.client.display_name or event.client.displayName or event.client.name }}</p>
</div>
<a class="small-box-footer" href="{% if dc['uchiwa'] %}{{ dc['uchiwa'] }}/#/client/{{ dc['name'] }}/{{ event.client.name }}?check={{ event.check.name }}{% else %}#{% endif %}" {% if dc['uchiwa'] %}target="_blank"{% endif %}>
<small>Detail</small>
<i class="fa fa-arrow-circle-right"></i>
</a>
</div>
</div>
{% if loop.last or loop.index0 % 3 == 2 %}</div>{% endif %}
{% else %}
<div class="row spacer">
<div class="col-xs-12">
<div class="small-box bg-green">
<div class="inner" style="text-align: center">
{% if appcfg.no_fail_image %}
<img src="{{ appcfg.no_fail_image }}" alt="All checks passing" />
{% else %}
<h2>All checks passing</h2>
{% endif %}
<div class="icon">
<i class="fa fa-check-circle"></i>
</div>
</div>
</div>
</div>
</div>
{% endfor %}

{% endblock %}
2 changes: 1 addition & 1 deletion templates/menu_detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Filter by<span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
{% for d in filter_data %}
<li><a href="{{ url_for('showgrid_filtered', d=dc['name'], subscriptions=d) }}">{{ d }}</a></li>
<li><a href="{{ url_for(request.url_rule.endpoint, d=dc['name'], filters=d) }}">{{ d }}</a></li>
{% endfor %}
</ul>

Expand Down
13 changes: 12 additions & 1 deletion templates/menu_main.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,25 @@
</li>
{% endif %}

<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Events<span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
{% for d in data %}
{% if d.name %}
<li><a href="{{ url_for('events', d=d.name) }}">{{ d.name }}</a></li>
{% endif %}
{% endfor %}
</ul>
</li>

{% if filter_data and filter_data | length > 0 %}
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Filter by<span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">

{% for d in filter_data %}

<li><a href="{{ url_for('filtered', subscriptions=d) }}">{{ d }}</a></li>
<li><a href="{{ url_for('filtered', filters=d) }}">{{ d }}</a></li>

{% endfor %}
</ul>
Expand Down

0 comments on commit 7909c1d

Please sign in to comment.