From 901adc49d5d6f8fb806b6f080c2b278752c1b385 Mon Sep 17 00:00:00 2001 From: Daniele Sluijters Date: Thu, 13 Mar 2014 11:42:33 +0100 Subject: [PATCH 01/11] Update requirements.txt. --- requirements.txt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/requirements.txt b/requirements.txt index f1c06db..f9f044a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,9 +1,9 @@ Flask==0.10.1 -Flask-WTF==0.8.4 -Jinja2==2.7 -MarkupSafe==0.18 -WTForms==1.0.4 -Werkzeug==0.9.3 -itsdangerous==0.22 -pypuppetdb==0.1.0 -requests==1.2.3 +Flask-WTF==0.9.4 +Jinja2==2.7.2 +MarkupSafe==0.19 +WTForms==1.0.5 +Werkzeug==0.9.4 +itsdangerous==0.23 +pypuppetdb==0.1.1 +requests==2.2.1 From 7dd01b49bc5e5c1e00a2694647c9dd6847c50f64 Mon Sep 17 00:00:00 2001 From: Daniele Sluijters Date: Thu, 13 Mar 2014 11:43:37 +0100 Subject: [PATCH 02/11] utils: Python 3 fix. --- puppetboard/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/puppetboard/utils.py b/puppetboard/utils.py index 03ecb85..608fbae 100644 --- a/puppetboard/utils.py +++ b/puppetboard/utils.py @@ -20,7 +20,7 @@ def get_or_abort(func, *args, **kwargs): """ try: return func(*args, **kwargs) - except HTTPError, e: + except HTTPError as e: abort(e.response.status_code) except ConnectionError: abort(500) From 64f453df093b150c56f8f618aa4621ad11e01171 Mon Sep 17 00:00:00 2001 From: Daniele Sluijters Date: Thu, 13 Mar 2014 11:46:29 +0100 Subject: [PATCH 03/11] python3: Fix urllib/unquote usage. --- puppetboard/app.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/puppetboard/app.py b/puppetboard/app.py index 0ac6db7..b17198e 100644 --- a/puppetboard/app.py +++ b/puppetboard/app.py @@ -4,7 +4,10 @@ from __future__ import absolute_import import os import logging import collections -import urllib +try: + from urllib import unquote +except ImportError: + from urllib.parse import unquote from datetime import datetime, timedelta from flask import ( @@ -305,7 +308,7 @@ def metrics(): @app.route('/metric/') def metric(metric): - name = urllib.unquote(metric) + name = unquote(metric) metric = puppetdb.metric(metric) return render_template( 'metric.html', From c588ee6ce800c4c525aabf3bb4a9fdef532f4a47 Mon Sep 17 00:00:00 2001 From: Daniele Sluijters Date: Thu, 13 Mar 2014 11:47:08 +0100 Subject: [PATCH 04/11] query: Allow to pass in query with or without []. --- puppetboard/app.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/puppetboard/app.py b/puppetboard/app.py index b17198e..66c7339 100644 --- a/puppetboard/app.py +++ b/puppetboard/app.py @@ -287,10 +287,14 @@ def query(): if app.config['ENABLE_QUERY']: form = QueryForm() if form.validate_on_submit(): + if form.query.data[0] == '[': + query = form.query.data + else: + query = '[{0}]'.format(form.query.data) result = get_or_abort( puppetdb._query, form.endpoints.data, - query='[{0}]'.format(form.query.data)) + query=query) return render_template('query.html', form=form, result=result) return render_template('query.html', form=form) else: From 9d1f2f725417ef283ca10a93bec9d9452725426d Mon Sep 17 00:00:00 2001 From: Daniele Sluijters Date: Thu, 13 Mar 2014 11:47:44 +0100 Subject: [PATCH 05/11] python3: Fix iterating over a dict. --- puppetboard/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/puppetboard/app.py b/puppetboard/app.py index 66c7339..ed1a52f 100644 --- a/puppetboard/app.py +++ b/puppetboard/app.py @@ -305,7 +305,7 @@ def query(): @app.route('/metrics') def metrics(): metrics = get_or_abort(puppetdb._query, 'metrics', path='mbeans') - for key, value in metrics.iteritems(): + for key, value in metrics.items(): metrics[key] = value.split('/')[3] return render_template('metrics.html', metrics=sorted(metrics.items())) From c4d1dd3596a0d530618e65947cd6008d972f4bf6 Mon Sep 17 00:00:00 2001 From: Daniele Sluijters Date: Thu, 13 Mar 2014 11:48:02 +0100 Subject: [PATCH 06/11] app: Use a ThreadPool to fetch metrics. --- puppetboard/app.py | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/puppetboard/app.py b/puppetboard/app.py index ed1a52f..141fe5f 100644 --- a/puppetboard/app.py +++ b/puppetboard/app.py @@ -9,6 +9,7 @@ try: except ImportError: from urllib.parse import unquote from datetime import datetime, timedelta +from multiprocessing.dummy import Pool as ThreadPool from flask import ( Flask, render_template, abort, url_for, @@ -91,19 +92,17 @@ def index(): # TODO: Would be great if we could parallelize this somehow, doing these # requests in sequence is rather pointless. prefix = 'com.puppetlabs.puppetdb.query.population' - num_nodes = get_or_abort( - puppetdb.metric, - "{0}{1}".format(prefix, ':type=default,name=num-nodes')) - num_resources = get_or_abort( - puppetdb.metric, - "{0}{1}".format(prefix, ':type=default,name=num-resources')) - avg_resources_node = get_or_abort( - puppetdb.metric, - "{0}{1}".format(prefix, ':type=default,name=avg-resources-per-node')) + pool = ThreadPool() + endpoints = [ + "{0}{1}".format(prefix, ':type=default,name=num-nodes'), + "{0}{1}".format(prefix, ':type=default,name=num-resources'), + "{0}{1}".format(prefix, ':type=default,name=avg-resources-per-node'), + ] + fetched_metrics = pool.map(puppetdb.metric, endpoints) metrics = { - 'num_nodes': num_nodes['Value'], - 'num_resources': num_resources['Value'], - 'avg_resources_node': "{0:10.0f}".format(avg_resources_node['Value']), + 'num_nodes': fetched_metrics[0]['Value'], + 'num_resources': fetched_metrics[1]['Value'], + 'avg_resources_node': "{0:10.0f}".format(fetched_metrics[2]['Value']), } nodes = puppetdb.nodes( From ce4c7a26cdf89dff39c9fb987dbda6a6d947cad2 Mon Sep 17 00:00:00 2001 From: Daniele Sluijters Date: Thu, 13 Mar 2014 11:49:00 +0100 Subject: [PATCH 07/11] Swap timestamp format to ISO and 24h clock. --- puppetboard/static/js/timestamps.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/puppetboard/static/js/timestamps.js b/puppetboard/static/js/timestamps.js index c682c09..a5dedd8 100644 --- a/puppetboard/static/js/timestamps.js +++ b/puppetboard/static/js/timestamps.js @@ -16,7 +16,7 @@ jQuery(function ($) { if (result == '') { tstamp.text('Unknown'); } else { - tstamp.text(localise_timestamp(tstring).format('LLLL')); + tstamp.text(localise_timestamp(tstring).format('MMM DD YYYY - HH:mm:ss')); }; }); From bcb45c24a437fbbdc79ca582ab2ee718da8da3d2 Mon Sep 17 00:00:00 2001 From: Daniele Sluijters Date: Thu, 13 Mar 2014 11:49:24 +0100 Subject: [PATCH 08/11] Switch the interface to Semantic-UI. --- puppetboard/static/css/puppetboard.css | 135 ++++++------------ puppetboard/static/js/tablesort.min.js | 9 ++ puppetboard/templates/400.html | 12 +- puppetboard/templates/403.html | 12 +- puppetboard/templates/404.html | 12 +- puppetboard/templates/500.html | 22 ++- puppetboard/templates/_macros.html | 14 +- puppetboard/templates/fact.html | 4 +- puppetboard/templates/facts.html | 6 +- puppetboard/templates/index.html | 184 +++++++++++++------------ puppetboard/templates/layout.html | 88 +++++------- puppetboard/templates/metric.html | 14 +- puppetboard/templates/node.html | 60 ++++---- puppetboard/templates/nodes.html | 57 ++++---- puppetboard/templates/query.html | 92 +++++-------- puppetboard/templates/report.html | 12 +- puppetboard/templates/reports.html | 2 +- 17 files changed, 327 insertions(+), 408 deletions(-) create mode 100644 puppetboard/static/js/tablesort.min.js diff --git a/puppetboard/static/css/puppetboard.css b/puppetboard/static/css/puppetboard.css index 46d002f..a00cbd0 100644 --- a/puppetboard/static/css/puppetboard.css +++ b/puppetboard/static/css/puppetboard.css @@ -1,104 +1,57 @@ body { - padding-top: 60px; + margin: 0; + font-family: "Open Sans", sans-serif; } -th.headerSortUp { - position: relative + +a { + color: #564F8A; + text-decoration: none; } -th.headerSortDown { - position: relative + +h1.ui.header.no-margin-bottom { + margin-bottom: 0; } -th.header { - position: relative + +.tablesorter-header-inner { + float: left; } -th.header:after { - content: "\f0dc"; - font-family: FontAwesome; - font-style: normal; - font-weight: normal; - text-decoration: inherit; - color: #000; - font-size: 18px; - padding-right: 0.5em; - float:right; + +th.tablesorter-headerAsc::after { + content: '\25b4' !important; + float: right; } -th.headerSortUp:after { - content: "\f0de"; - font-family: FontAwesome; - font-style: normal; - font-weight: normal; - text-decoration: inherit; - color: #000; - font-size: 18px; - padding-right: 0.5em; - float:right; + +th.tablesorter-headerDesc::after { + content: '\25be' !important; + float: right; } -th.headerSortDown:after { - content: "\f0dd"; - font-family: FontAwesome; - font-style: normal; - font-weight: normal; - text-decoration: inherit; - color: #000; - font-size: 18px; - padding-right: 0.5em; - float:right; + +.ui.grid.padding-bottom { + padding-bottom: 40px !important; } -.stat { - margin-bottom: 40px; + +.status { + width: 47%; + text-align: center; + display: block; } -.navbar .brand:hover { - color: #fff; +.count { + width: 21%; + text-align: center; + display: block; } -.table tbody tr.error>td { - background-color: #f2dede; + +.no-margin-top { + margin-top: -35px !important; } -h1.error { - color: rgb(223, 46, 27); + +.absolute { + position: fixed; + bottom: 0; + width: 100%; + background: #E8E8E8; } -h1.success { - color: #18BC9C; -} -h1.noop { - color:#aaa; -} -tr.event { - cursor: pointer; -} -td.message { - padding: 0; - border: 0; - background-color: #FFFFE9; -} -div[id^='message-event'] { - display: none; - padding: 4px 15px 4px 15px; -} -.label-count { - width:25px; - text-align:center; -} -.label-time { - width:73px; - text-align:center; -} -.label-status { - width:100px; - text-align:center; -} -.label-nothing { - background-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); -} -.btn-lastreport { - width:100px; + +.absolute div { + padding: 1em; } diff --git a/puppetboard/static/js/tablesort.min.js b/puppetboard/static/js/tablesort.min.js new file mode 100644 index 0000000..ab17511 --- /dev/null +++ b/puppetboard/static/js/tablesort.min.js @@ -0,0 +1,9 @@ +/* + A simple, lightweight jQuery plugin for creating sortable tables. + https://github.com/kylefox/jquery-tablesort + Version 0.0.2 +*/ +$(function(){var a=window.jQuery;a.tablesort=function(d,c){var e=this;this.$table=d;this.$thead=this.$table.find("thead");this.settings=a.extend({},a.tablesort.defaults,c);this.$table.find("th").bind("click.tablesort",function(){e.sort(a(this))});this.direction=this.$th=this.index=null};a.tablesort.prototype={sort:function(d,c){var e=new Date,b=this,g=this.$table,n=0b.value?1*c:a.value -
-
-

Bad Request

-

The request sent to PuppetDB was invalid. This is usually caused by using an unsupported operator.

-
-
- +{% block content %} +

Bad Request

+

The request sent to PuppetDB was invalid. This is usually caused by using an unsupported operator.

{% endblock %} diff --git a/puppetboard/templates/403.html b/puppetboard/templates/403.html index bfe77d0..a5055d3 100644 --- a/puppetboard/templates/403.html +++ b/puppetboard/templates/403.html @@ -1,11 +1,5 @@ {% extends 'layout.html' %} -{% block row_fluid %} -
-
-
-

Permission Denied

-

What you were looking for has been disabled by the administrator.

-
-
-
+{% block content %} +

Permission Denied

+

What you were looking for has been disabled by the administrator.

{% endblock %} diff --git a/puppetboard/templates/404.html b/puppetboard/templates/404.html index e45a201..e9a99ac 100644 --- a/puppetboard/templates/404.html +++ b/puppetboard/templates/404.html @@ -1,11 +1,5 @@ {% extends 'layout.html' %} -{% block row_fluid %} -
-
-
-

Not Found

-

What you were looking for could not be found in PuppetDB.

-
-
-
+{% block content%} +

Not Found

+

What you were looking for could not be found in PuppetDB.

{% endblock %} diff --git a/puppetboard/templates/500.html b/puppetboard/templates/500.html index b79f451..b35ae0f 100644 --- a/puppetboard/templates/500.html +++ b/puppetboard/templates/500.html @@ -1,16 +1,10 @@ {% extends 'layout.html' %} -{% block row_fluid %} -
-
-
-

Internal Server Error

-

This error usually occurs because: -

    -
  • We were unable to reach PuppetDB;
  • -
  • The query to be executed was malformed resulting in an incorrectly encoded request.
  • -

-

Please have a look at the log output for further information.

-
-
-
+{% block content %} +

Internal Server Error

+

This error usually occurs because: +

    +
  • We were unable to reach PuppetDB;
  • +
  • The query to be executed was malformed resulting in an incorrectly encoded request.
  • +

+

Please have a look at the log output for further information.

{% endblock %} diff --git a/puppetboard/templates/_macros.html b/puppetboard/templates/_macros.html index ba70a69..3c0bad5 100644 --- a/puppetboard/templates/_macros.html +++ b/puppetboard/templates/_macros.html @@ -1,8 +1,8 @@ {% macro facts_table(facts, autofocus=False, condensed=False, show_node=False, show_value=True, link_facts=False, margin_top=20, margin_bottom=20) -%} -
- +
+
- +
{% if show_node %} @@ -96,10 +96,10 @@ {%- endmacro %} {% macro reports_table(reports, nodename, condensed=False, hash_truncate=False, show_conf_col=True, show_agent_col=True, show_host_col=True) -%} -
+
Only showing the last ten reports.
-
+
@@ -119,7 +119,7 @@ {% for report in reports %} {% if hash_truncate %} - {% set rep_hash = "%s…"|format(report.hash_[0:6])|safe %} + {% set rep_hash = "%s…"|format(report.hash_[0:10])|safe %} {% else %} {% set rep_hash = report.hash_ %} {% endif %} @@ -139,7 +139,7 @@ {% endif %} {% if show_host_col %} - + {% endif %} {% endfor %} diff --git a/puppetboard/templates/fact.html b/puppetboard/templates/fact.html index 9950d74..b6a9782 100644 --- a/puppetboard/templates/fact.html +++ b/puppetboard/templates/fact.html @@ -2,8 +2,8 @@ {% import '_macros.html' as macros %} {% block content %}

{{name}}{% if value %}/{{value}}{% endif %} ({{facts|length}})

-{{macros.facts_graph(facts, autofocus=True, show_node=True, margin_bottom=10)}} -{{macros.facts_graph_value(facts, autofocus=True, show_node=True, margin_bottom=10)}} +{#{{macros.facts_graph(facts, autofocus=True, show_node=True, margin_bottom=10)}}# +{{macros.facts_graph_value(facts, autofocus=True, show_node=True, margin_bottom=10)}}#} {% if value %} {{macros.facts_table(facts, autofocus=True, show_node=True, show_value=False, margin_bottom=10)}} {% else %} diff --git a/puppetboard/templates/facts.html b/puppetboard/templates/facts.html index 44177ec..98d390c 100644 --- a/puppetboard/templates/facts.html +++ b/puppetboard/templates/facts.html @@ -1,11 +1,11 @@ {% extends 'layout.html' %} {% block content %} -
- +
+
{%- for key,facts_list in facts_dict %} - {{key}} + {{key}}
Start time
{{report.agent_version}}{{nodename}}{{ report.node }}
- - - - - - - - - {% for node in nodes %} - {% if node.status != 'unchanged' %} - - - - diff --git a/puppetboard/templates/layout.html b/puppetboard/templates/layout.html index 8c4d28c..b7697d4 100644 --- a/puppetboard/templates/layout.html +++ b/puppetboard/templates/layout.html @@ -10,7 +10,7 @@ - diff --git a/puppetboard/templates/query.html b/puppetboard/templates/query.html index 757049b..10089e5 100644 --- a/puppetboard/templates/query.html +++ b/puppetboard/templates/query.html @@ -27,7 +27,7 @@ {% endfor %} {{ form.hidden_tag() }} - +
StatusHostname
- - {{node.status}} - - {% if node.status=='unreported'%} - {{ node.unreported_time }} - {% else %} - {% if node.events['failures'] %}{{node.events['failures']}}{% else %}0{% endif%} - {% if node.events['successes'] %}{{node.events['successes']}}{% else %}0{% endif%} - {% endif %} - {{ node.name }} - {% if node.unreported_time != None or node.status != 'unreported' %} - Latest Report - {% else %} - No Report +

Nodes status detail ({{nodes|length}})

+ + + + + + + + + + {% for node in nodes %} + {% if node.status != 'unchanged' %} + + + + + + {% endif %} + {% endfor %} + +
StatusHostname
+ + {{node.status}} + + {% if node.status=='unreported'%} + {{ node.unreported_time }} + {% else %} + {% if node.events['failures'] %}{{node.events['failures']}}{% else %}0{% endif%} + {% if node.events['successes'] %}{{node.events['successes']}}{% else %}0{% endif%} + {% endif %} + + {{ node.name }} + + + + +
{% else %} -

Nodes status detail

-
- Nothing seems to be changing. -
+

Nodes status detail

+
+ Nothing seems to be changing. +
{% endif %} -{% endblock row_fluid %} +{% endblock content %} diff --git a/puppetboard/templates/layout.html b/puppetboard/templates/layout.html index a49e942..c8fef60 100644 --- a/puppetboard/templates/layout.html +++ b/puppetboard/templates/layout.html @@ -2,66 +2,52 @@ - Puppetᴃoard - - - + Puppetboard + + + + -
- +
{% if node.report_timestamp %} - - + + {% endif %}