Merge pull request #28 from digitalmediacenter/improve-nodestatus

Enhance node status feature in overview and nodes
This commit is contained in:
Daniele Sluijters
2013-11-05 03:01:02 -08:00
6 changed files with 110 additions and 82 deletions

View File

@@ -101,40 +101,35 @@ def index():
'avg_resources_node': "{0:10.6f}".format(avg_resources_node['Value']), 'avg_resources_node': "{0:10.6f}".format(avg_resources_node['Value']),
} }
latest_event_count = puppetdb._query( nodes = puppetdb.nodes(with_status=True)
'aggregate-event-counts',
query='["=", "latest-report?", true]',
summarize_by='certname')
latest_event_count['noopskip'] = ( nodes_overview = []
latest_event_count['noops'] + latest_event_count['skips']) stats = {
'changed': 0,
'unchanged': 0,
'failed': 0,
'unreported': 0,
}
latest_events = puppetdb._query( for node in nodes:
'event-counts', if node.status == 'unreported':
query='["=", "latest-report?", true]', stats['unreported'] += 1
summarize_by='certname') elif node.status == 'changed':
stats['changed'] += 1
elif node.status == 'failed':
stats['failed'] += 1
else:
stats['unchanged'] += 1
unreported = [] if node.status != 'unchanged':
unresponsive_window = datetime.utcnow() - ( nodes_overview.append(node)
timedelta(hours=app.config['UNRESPONSIVE_HOURS']))
for node in puppetdb.nodes():
try:
node_last_seen = node.report_timestamp.replace(tzinfo=None)
if node_last_seen < unresponsive_window:
delta = (datetime.utcnow() - node_last_seen)
node.noresponse = str(delta.days) + "d "
node.noresponse += str(int(delta.seconds / 3600)) + "h "
node.noresponse += str(int((delta.seconds % 3600) / 60)) + "m"
unreported.append(node)
except AttributeError:
unreported.append(node)
return render_template( return render_template(
'index.html', 'index.html',
metrics=metrics, metrics=metrics,
latest_event_count=latest_event_count, nodes=nodes_overview,
latest_events=latest_events, stats=stats
unreported=unreported) )
@app.route('/nodes') @app.route('/nodes')
@@ -149,27 +144,13 @@ def nodes():
provide a search feature instead. provide a search feature instead.
""" """
status_arg = request.args.get('status', '') status_arg = request.args.get('status', '')
latest_events = puppetdb._query(
'event-counts',
query='["=", "latest-report?", true]',
summarize_by='certname')
nodes = [] nodes = []
for node in yield_or_stop(puppetdb.nodes()): for node in yield_or_stop(puppetdb.nodes(with_status=True)):
# check if node name is contained in any of the
# event-counts (grouped by certname)
status = [
s for s in latest_events if
s['subject']['title'] == node.name]
if status:
node.status = status[0]
else:
node.status = {}
if status_arg: if status_arg:
if node.status.has_key(status_arg) and node.status[status_arg]: if node.status == status_arg:
nodes.append(node) nodes.append(node)
else: else:
nodes.append(node) nodes.append(node)
return Response(stream_with_context( return Response(stream_with_context(
stream_template('nodes.html', nodes=nodes))) stream_template('nodes.html', nodes=nodes)))

View File

@@ -2,15 +2,22 @@ $ = jQuery
$ -> $ ->
$('.nodes').tablesorter( $('.nodes').tablesorter(
headers: headers:
3: 4:
sorter: false sorter: false
sortList: [[0,0]] sortList: [[1,0]]
) )
$('.facts').tablesorter( $('.facts').tablesorter(
sortList: [[0,0]] sortList: [[0,0]]
) )
$('.dashboard').tablesorter(
headers:
2:
sorter: false
sortList: [[0, 1]]
)
$('input.filter-table').parent('div').removeClass('hide') $('input.filter-table').parent('div').removeClass('hide')
$("input.filter-table").on "keyup", (e) -> $("input.filter-table").on "keyup", (e) ->
rex = new RegExp($(this).val(), "i") rex = new RegExp($(this).val(), "i")

View File

@@ -61,12 +61,29 @@ h1.success {
h1.noop { h1.noop {
color:#aaa; color:#aaa;
} }
.numtag { .label-count {
width:20px; width:25px;
text-align:center;
}
.label-time {
width:73px;
text-align:center;
}
.label-status {
width:100px;
text-align:center; text-align:center;
} }
.label-nothing { .label-nothing {
background-color:#ddd; background-color:#ddd;
width:20px;
color:#ddd; color:#ddd;
} }
.label.label-failed {
background-color: rgb(231, 76, 60);
}
.label.label-changed {
background-color: rgb(24, 188, 156);
}
.label.label-unreported {
background-color: rgb(231, 76, 60);
background-color: rgb(129, 145, 146);
}

View File

@@ -19,6 +19,13 @@
sortList: [[0, 0]] sortList: [[0, 0]]
}); });
$('.dashboard').tablesorter({
headers: {
2: { sorter: false }
},
sortList: [[0, 1]]
});
$('input.filter-table').parent('div').removeClass('hide'); $('input.filter-table').parent('div').removeClass('hide');
$("input.filter-table").on("keyup", function(e) { $("input.filter-table").on("keyup", function(e) {

View File

@@ -1,25 +1,33 @@
{% extends 'layout.html' %} {% extends 'layout.html' %}
{% block row_fluid %} {% block row_fluid %}
<div class="container" style="margin-bottom:55px;"> <div class="container" style="margin-bottom:55px;">
<div class="row"> <div class="row">
<div class="span12"> <div class="span12">
<div class="span4 stat"> <div class="span4 stat">
<a href="nodes?status=failures"> <a href="nodes?status=failed">
<h1 class="error">{{latest_event_count['failures']}} <small>node(s)</small></h1> <h1 class="error">{{stats['failed']}}
<small>{% if stats['failed']== 1 %} node {% else %} nodes {% endif %}</small>
</h1>
</a> </a>
<span>with failures in latest reports</span> <span>with status failed</span>
</div> </div>
<div class="span4 stat"> <div class="span4 stat">
<a href="nodes?status=successes"> <a href="nodes?status=changed">
<h1 class="success">{{latest_event_count['successes']}} <small>node(s)</small></h1> <h1 class="success">{{stats['changed']}}
<small>{% if stats['changed']== 1 %} node {% else %} nodes {% endif %}</small>
</h1>
</a> </a>
<span>with successes in latest reports</span> <span>with status changed</span>
</div> </div>
<div class="span4 stat"> <div class="span4 stat">
<h1 class="noop">{{ unreported|length }} <small>unreported</small></h1> <a href="nodes?status=unreported">
<h1 class="noop">{{ stats['unreported'] }}
<small>{% if stats['unreported']== 1 %} node {% else %} nodes {% endif %}</small>
</h1>
</a>
<span> <span>
{% if unreported|length == 1 %} node {% else %} nodes {% endif %} unreported in the last {{ config.UNRESPONSIVE_HOURS }} hours
in the last {{ config.UNRESPONSIVE_HOURS }} hours
</span> </span>
</div> </div>
</div> </div>
@@ -44,34 +52,38 @@
<div class="row"> <div class="row">
<div class="span12"> <div class="span12">
<h2>Nodes unresponsive in the last {{ config.UNRESPONSIVE_HOURS }} hours</h2> <h2>Node Status Detail</h2>
<table class='nodes table table-striped table-condensed'> <table class='dashboard table table-striped table-condensed'>
<tbody class="searchable"> <thead>
{% for node in unreported %}
<tr> <tr>
<td style="width:110px;"><span class="label label-important">No Report</span></td> <th style="width:220px;">Status</th>
<td>{{ node.noresponse }}</td> <th style="width:600px;">Hostname</th>
<td><a href="{{url_for('node', node_name=node.name)}}">{{ node.name }}</a></td> <th style="width:120px;"></th>
<td style="width:120px;"><a class="btn btn-small btn-primary" href="{{url_for('report_latest', node_name=node.name)}}">Latest Report</a></td>
</tr> </tr>
{% endfor %} </thead>
</tbody>
</table>
<h2>Latest reports with events</h2>
<table class='nodes table table-striped table-condensed'>
<tbody class="searchable"> <tbody class="searchable">
{% for event in latest_events %} {% for node in nodes %}
{% if node.status != 'unchanged' %}
<tr> <tr>
<td style="width:110px;"> <td>
{% if event['failures'] %}<span class="label label-important numtag">{{event['failures']}}</span>{% else %}<span class="label numtag">0</span>{% endif%} <a href="{{url_for('report_latest', node_name=node.name)}}">
{% if event['successes'] %}<span class="label label-success numtag">{{event['successes']}}</span>{% else %}<span class="label numtag">0</span>{% endif%} <span class="label label-status label-{{node.status}}">{{node.status}}</span>
</a>
{% if node.status=='unreported'%}
<span class="label label-time label-unreported"> {{ node.unreported_time }} </label>
{% else %}
{% if node.events['failures'] %}<span class="label label-important label-count">{{node.events['failures']}}</span>{% else %}<span class="label label-count">0</span>{% endif%}
{% if node.events['successes'] %}<span class="label label-success label-count">{{node.events['successes']}}</span>{% else %}<span class="label label-count">0</span>{% endif%}
{% endif %}
</td> </td>
<td style="width:700px;"><a href="{{url_for('node', node_name=event['subject']['title'])}}">{{event['subject']['title']}}</a></td> <td><a href="{{url_for('node', node_name=node.name)}}">{{ node.name }}</a></td>
<td style="width:120px;"><a class="btn btn-small btn-primary" href="{{url_for('report_latest', node_name=event['subject']['title'])}}">Latest Report</a></td> <td><a class="btn btn-small btn-primary" href="{{url_for('report_latest', node_name=node.name)}}">Latest Report</a></td>
</tr> </tr>
{% endif %}
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -29,10 +29,14 @@
{% for node in nodes %} {% for node in nodes %}
<tr> <tr>
<td><a href="{{url_for('report_latest', node_name=node.name)}}"> <td><a href="{{url_for('report_latest', node_name=node.name)}}">
{% if node.status['failures'] %}<span class="label numtag label-important">{{node.status['failures']}}</span>{% else %}<span class="label label-nothing">0</span>{% endif %} <span class="label label-status label-{{ node.status }}">{{ node.status }}</span>
{% if node.status['successes'] %}<span class="label numtag label-success">{{node.status['successes']}}</span>{% else %}<span class="label label-nothing">0</span>{% endif %}
{% if node.status['noops'] or node.status['skips'] %}<span class="label numtag">{{node.status['skips']+node.status['noops']}}</span>{% else %}<span class="label label-nothing">0</span>{% endif %}
</a> </a>
{% if node.status=='unreported'%}
<span class="label label-time label-unreported"> {{ node.unreported_time }} </label>
{% else %}
{% if node.events['failures'] %}<span class="label label-count label-important">{{node.events['failures']}}</span>{% else %}<span class="label label-count">0</span>{% endif%}
{% if node.events['successes'] %}<span class="label label-count label-success">{{node.events['successes']}}</span>{% else %}<span class="label label-count">0</span>{% endif%}
{% endif %}
</td> </td>
<td><a href="{{url_for('node', node_name=node.name)}}">{{node.name}}</a></td> <td><a href="{{url_for('node', node_name=node.name)}}">{{node.name}}</a></td>
<td rel="utctimestamp">{{node.catalog_timestamp}}</td> <td rel="utctimestamp">{{node.catalog_timestamp}}</td>