diff --git a/puppetboard/app.py b/puppetboard/app.py index fab3d06..57eca08 100644 --- a/puppetboard/app.py +++ b/puppetboard/app.py @@ -949,3 +949,83 @@ def catalog_compare(env, compare, against): else: log.warn('Access to catalog interface disabled by administrator') abort(403) + +@app.route('/radiator', defaults={'env': app.config['DEFAULT_ENVIRONMENT']}) +@app.route('//radiator') +def radiator(env): + """This view generates a simplified monitoring page + akin to the radiator view in puppet dashboard + """ + envs = environments() + check_env(env, envs) + + if env == '*': + query = None + metrics = get_or_abort( + puppetdb.metric, + 'puppetlabs.puppetdb.population:name=num-nodes') + num_nodes = metrics['Value'] + else: + query = '["and", {0}]]'.format( + ",".join('["=", "{0}", "{1}"]'.format(field, env) + for field in ['catalog_environment', 'facts_environment'])) + metrics = get_or_abort( + puppetdb._query, + 'nodes', + query='["extract", [["function", "count"]],{0}'.format( + query)) + num_nodes = metrics[0]['count'] + + + nodes = puppetdb.nodes( + query=query, + unreported=app.config['UNRESPONSIVE_HOURS'], + with_status=True + ) + + + stats = { + 'changed_percent': 0, + 'changed': 0, + 'failed_percent': 0, + 'failed': 0, + 'noop_percent': 0, + 'noop': 0, + 'skipped_percent': 0, + 'skipped': 0, + 'unchanged_percent': 0, + 'unchanged': 0, + 'unreported_percent': 0, + 'unreported': 0, + } + + + + for node in nodes: + if node.status == 'unreported': + stats['unreported'] += 1 + elif node.status == 'changed': + stats['changed'] += 1 + elif node.status == 'failed': + stats['failed'] += 1 + elif node.status == 'noop': + stats['noop'] += 1 + elif node.status == 'skipped': + stats['skipped'] +=1 + else: + stats['unchanged'] += 1 + + + stats['changed_percent'] = int(100 * stats['changed'] / float(num_nodes)) + stats['failed_percent'] = int(100 * stats['failed'] / float(num_nodes)) + stats['noop_percent'] = int(100 * stats['noop'] / float(num_nodes)) + stats['skipped_percent'] = int(100 * stats['skipped'] / float(num_nodes)) + stats['unchanged_percent'] = int(100 * stats['unchanged'] / float(num_nodes)) + stats['unreported_percent'] = int(100 * stats['unreported'] / float(num_nodes)) + + + return render_template( + 'radiator.html', + stats=stats, + total=num_nodes + ) diff --git a/puppetboard/static/css/radiator.css b/puppetboard/static/css/radiator.css new file mode 100644 index 0000000..7ad31ba --- /dev/null +++ b/puppetboard/static/css/radiator.css @@ -0,0 +1,42 @@ +html,body,div,span,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,code,del,dfn,em,img,q,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td {margin:0;padding:0;border:0;font-weight:inherit;font-style:inherit;font-size:100%;font-family:inherit;vertical-align:baseline;} +body{line-height:20px;} +table{border-collapse:separate;border-spacing:0;} +caption,th,td {text-align:left;font-weight:normal;} +table,td,th {vertical-align:middle;} +blockquote:before,blockquote:after,q:before,q:after {content:"";} +blockquote,q {quotes:"" "";} +a img {border:none;} +ul {list-style-position:inside;} +body.radiator_controller {font-size:1000%;line-height:1;font-family:"Helvetica Neue",Arial,Helvetica,sans-serif;background-color:#000;} +body.radiator_controller table.node_summary {padding:20px;position:absolute;height:100%;width:100%;} +body.radiator_controller table.node_summary .count_column {min-width:2em;width:2em;} +body.radiator_controller table.node_summary tr:last-child td {border-bottom:none;} +body.radiator_controller table.node_summary tr:last-child td .label {border-left:0px #000 solid;} +body.radiator_controller table.node_summary tr.unreported .percent {background-color:#ee7722;border-radius:0 3px 3px 0;} +body.radiator_controller table.node_summary tr.unreported .label,body.radiator_controller table.node_summary tr.unreported .count {color:#ee7722;} +body.radiator_controller table.node_summary tr.unreported .label {border-left:1px #333 dashed;} +body.radiator_controller table.node_summary tr.failed .percent {background-color:#cc2211;border-radius:0 3px 3px 0;} +body.radiator_controller table.node_summary tr.failed .label,body.radiator_controller table.node_summary tr.failed .count {color:#cc2211;} +body.radiator_controller table.node_summary tr.failed .label {border-left:1px #333 dashed;} +body.radiator_controller table.node_summary tr.noop .percent {background-color:#eddc21;border-radius:0 3px 3px 0;} +body.radiator_controller table.node_summary tr.noop .label,body.radiator_controller table.node_summary tr.noop .count {color:#eddc21;} +body.radiator_controller table.node_summary tr.noop .label {border-left:1px #333 dashed;} +body.radiator_controller table.node_summary tr.changed .percent {background-color:#009933;border-radius:0 3px 3px 0;} +body.radiator_controller table.node_summary tr.changed .label,body.radiator_controller table.node_summary tr.changed .count {color:#009933;} +body.radiator_controller table.node_summary tr.changed .label {border-left:1px #333 dashed;} +body.radiator_controller table.node_summary tr.unchanged .percent {background-color:#2198ed;border-radius:0 3px 3px 0;} +body.radiator_controller table.node_summary tr.unchanged .label,body.radiator_controller table.node_summary tr.unchanged .count {color:#2198ed;} +body.radiator_controller table.node_summary tr.unchanged .label {border-left:1px #333 dashed;} +body.radiator_controller table.node_summary tr.total {color:#fff;background-color:#181818;} +body.radiator_controller table.node_summary tr.total .percent {background-color:white;border-radius:0 3px 3px 0;} +body.radiator_controller table.node_summary tr.total .label,body.radiator_controller table.node_summary tr.total .count {color:white;} +body.radiator_controller table.node_summary tr.total .label {border-left:1px #333 dashed;} +body.radiator_controller table.node_summary tr.total .percent {display:none;} +body.radiator_controller table.node_summary tr.total td {border-top:1px solid #fff;} +body.radiator_controller table.node_summary tr td {color:#ccc;font-weight:normal;position:relative;border-bottom:1px solid #333;vertical-align:baseline;} +body.radiator_controller table.node_summary tr td div {position:relative;height:100%;} +body.radiator_controller table.node_summary tr td .percent {color:#000;position:absolute;top:0;left:0;height:100%;overflow:hidden;} +body.radiator_controller table.node_summary tr td .percent span {margin-left:0.1em;} +body.radiator_controller table.node_summary tr td .label {position:relative;height:100%;} +body.radiator_controller table.node_summary tr td .label span {margin-left:0.1em;} +body.radiator_controller table.node_summary tr td .count {text-align:right;width:1.75em;display:inline-block;font-weight:bold;margin-top:-0.12em;} diff --git a/puppetboard/static/js/radiator.js b/puppetboard/static/js/radiator.js new file mode 100644 index 0000000..63bd6a6 --- /dev/null +++ b/puppetboard/static/js/radiator.js @@ -0,0 +1,21 @@ +function resizeMe() { + var preferredHeight = 944; + var displayHeight = $(window).height(); + var percentageHeight = displayHeight / preferredHeight; + + var preferredWidth = 1100; + var displayWidth = $(window).width(); + var percentageWidth = displayWidth / preferredWidth; + + var newFontSize; + if (percentageHeight < percentageWidth) { + newFontSize = Math.floor("960" * percentageHeight) - 30; + } else { + newFontSize = Math.floor("960" * percentageWidth) - 30; + } + $("body").css("font-size", newFontSize + "%") +} + +$(document).ready(function() { + $(window).on('resize', resizeMe).trigger('resize'); +}) diff --git a/puppetboard/templates/layout.html b/puppetboard/templates/layout.html index 9600fa9..0f9829b 100644 --- a/puppetboard/templates/layout.html +++ b/puppetboard/templates/layout.html @@ -32,6 +32,7 @@ ('metrics', 'Metrics'), ('inventory', 'Inventory'), ('catalogs', 'Catalogs'), + ('radiator', 'Radiator'), ('query', 'Query'), ] %} + + + Puppetboard + {% if config.REFRESH_RATE > 0 %} + + {% endif %} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ {{stats['failed']}} + +
+

+ Failed +

+

+ Failed +

+
+
+ {{stats['unreported']}} + +
+

+ Unreported +

+

+ Unreported +

+
+
+ {{stats['noop']}} + +
+

+ Pending +

+

+ Pending +

+
+
+ {{stats['changed']}} + +
+

+ Changed +

+

+ Changed +

+
+
+ {{stats['unchanged']}} + +
+

+ Unchanged +

+

+ Unchanged +

+
+
+ {{total}} + +
+

+ Total +

+
+
+ + diff --git a/screenshots/radiator.png b/screenshots/radiator.png new file mode 100644 index 0000000..ff73731 Binary files /dev/null and b/screenshots/radiator.png differ