Support PuppetDB API v3.

Recently changes were made to pypuppetdb to support, at a basic level,
the v3 API introduced with PuppetDB 1.5.

This commit changes some internals of Puppetboard to handle the new
situation:
 * The experimental endpoints are gone, so is the ExperimentalDisabled
   Error;
 * v2 API can no longer access Reports/Events so we now check that we're
   talking at least v3 API;
 * Introduce a configuration setting PUPPETDB_API which takes an integer
   repersenting the API version we want to talk.
This commit is contained in:
Daniele Sluijters
2013-10-11 11:17:53 +02:00
parent 3b4db8f37e
commit cc87e54cea
5 changed files with 17 additions and 20 deletions

View File

@@ -12,7 +12,6 @@ from flask import (
) )
from pypuppetdb import connect from pypuppetdb import connect
from pypuppetdb.errors import ExperimentalDisabledError
from puppetboard.forms import QueryForm from puppetboard.forms import QueryForm
from puppetboard.utils import ( from puppetboard.utils import (
@@ -27,13 +26,13 @@ app.config.from_envvar('PUPPETBOARD_SETTINGS', silent=True)
app.secret_key = os.urandom(24) app.secret_key = os.urandom(24)
puppetdb = connect( puppetdb = connect(
api_version=app.config['PUPPETDB_API'],
host=app.config['PUPPETDB_HOST'], host=app.config['PUPPETDB_HOST'],
port=app.config['PUPPETDB_PORT'], port=app.config['PUPPETDB_PORT'],
ssl=app.config['PUPPETDB_SSL'], ssl=app.config['PUPPETDB_SSL'],
ssl_key=app.config['PUPPETDB_KEY'], ssl_key=app.config['PUPPETDB_KEY'],
ssl_cert=app.config['PUPPETDB_CERT'], ssl_cert=app.config['PUPPETDB_CERT'],
timeout=app.config['PUPPETDB_TIMEOUT'], timeout=app.config['PUPPETDB_TIMEOUT'],)
experimental=app.config['PUPPETDB_EXPERIMENTAL'])
numeric_level = getattr(logging, app.config['LOGLEVEL'].upper(), None) numeric_level = getattr(logging, app.config['LOGLEVEL'].upper(), None)
if not isinstance(numeric_level, int): if not isinstance(numeric_level, int):
@@ -58,7 +57,8 @@ def not_found(e):
@app.errorhandler(412) @app.errorhandler(412)
def precond_failed(e): def precond_failed(e):
"""We're slightly abusing 412 to handle ExperimentalDisabled errors.""" """We're slightly abusing 412 to handle missing features
depending on the API version."""
return render_template('412.html'), 412 return render_template('412.html'), 412
@app.errorhandler(500) @app.errorhandler(500)
@@ -112,7 +112,7 @@ def node(node_name):
""" """
node = get_or_abort(puppetdb.node, node_name) node = get_or_abort(puppetdb.node, node_name)
facts = node.facts() facts = node.facts()
if app.config['PUPPETDB_EXPERIMENTAL']: if app.config['PUPPETDB_API'] > 2:
reports = ten_reports(node.reports()) reports = ten_reports(node.reports())
else: else:
reports = iter([]) reports = iter([])
@@ -123,21 +123,21 @@ def node(node_name):
def reports(): def reports():
"""Doesn't do much yet but is meant to show something like the reports of """Doesn't do much yet but is meant to show something like the reports of
the last half our, something like that.""" the last half our, something like that."""
if app.config['PUPPETDB_EXPERIMENTAL']: if app.config['PUPPETDB_API'] > 2:
return render_template('reports.html') return render_template('reports.html')
else: else:
log.warn('Access to experimental endpoint not allowed.') log.warn('PuppetDB API prior to v3 cannot access reports.')
abort(412) abort(412)
@app.route('/reports/<node>') @app.route('/reports/<node>')
def reports_node(node): def reports_node(node):
"""Fetches all reports for a node and processes them eventually rendering """Fetches all reports for a node and processes them eventually rendering
a table displaying those reports.""" a table displaying those reports."""
if app.config['PUPPETDB_EXPERIMENTAL']: if app.config['PUPPETDB_API'] > 2:
reports = ten_reports(yield_or_stop( reports = ten_reports(yield_or_stop(
puppetdb.reports('["=", "certname", "{0}"]'.format(node)))) puppetdb.reports('["=", "certname", "{0}"]'.format(node))))
else: else:
log.warn('Access to experimental endpoint not allowed.') log.warn('PuppetDB API prior to v3 cannot access reports.')
abort(412) abort(412)
return render_template('reports_node.html', reports=reports, return render_template('reports_node.html', reports=reports,
nodename=node) nodename=node)
@@ -146,10 +146,10 @@ def reports_node(node):
def report(node, report_id): def report(node, report_id):
"""Displays a single report including all the events associated with that """Displays a single report including all the events associated with that
report and their status.""" report and their status."""
if app.config['PUPPETDB_EXPERIMENTAL']: if app.config['PUPPETDB_API'] > 2:
reports = puppetdb.reports('["=", "certname", "{0}"]'.format(node)) reports = puppetdb.reports('["=", "certname", "{0}"]'.format(node))
else: else:
log.warn('Access to experimental endpoint not allowed.') log.warn('PuppetDB API prior to v3 cannot access reports.')
abort(412) abort(412)
for report in reports: for report in reports:

View File

@@ -4,7 +4,7 @@ PUPPETDB_SSL=False
PUPPETDB_KEY=None PUPPETDB_KEY=None
PUPPETDB_CERT=None PUPPETDB_CERT=None
PUPPETDB_TIMEOUT=20 PUPPETDB_TIMEOUT=20
PUPPETDB_EXPERIMENTAL=False PUPPETDB_API=3
DEV_LISTEN_HOST='127.0.0.1' DEV_LISTEN_HOST='127.0.0.1'
DEV_LISTEN_PORT=5000 DEV_LISTEN_PORT=5000
LOGLEVEL='info' LOGLEVEL='info'

View File

@@ -3,8 +3,8 @@
<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">
<h2>Experimental Disabled</h2> <h2>Feature unavailable</h2>
<p>You're trying to access a feature restricted to PuppetDB's Experimental API but haven't configured Puppetboard to allow this.</p> <p>You've configured Puppetboard with an API version that does not support this feature.</p>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -27,7 +27,7 @@
</tbody> </tbody>
</table> </table>
</div> </div>
{% if config.PUPPETDB_EXPERIMENTAL %} {% if config.PUPPETDB_API > 2 %}
<div class="span4"> <div class="span4">
<h1>Facts</h1> <h1>Facts</h1>
{{macros.facts_table(facts, condensed=True, margin_top=10)}} {{macros.facts_table(facts, condensed=True, margin_top=10)}}

View File

@@ -2,7 +2,7 @@ from __future__ import absolute_import
from __future__ import unicode_literals from __future__ import unicode_literals
from requests.exceptions import HTTPError, ConnectionError from requests.exceptions import HTTPError, ConnectionError
from pypuppetdb.errors import EmptyResponseError, ExperimentalDisabledError from pypuppetdb.errors import EmptyResponseError
from flask import abort from flask import abort
@@ -18,8 +18,6 @@ def get_or_abort(func, *args, **kwargs):
abort(e.response.status_code) abort(e.response.status_code)
except ConnectionError: except ConnectionError:
abort(500) abort(500)
except ExperimentalDisabledError:
abort(412)
except EmptyResponseError: except EmptyResponseError:
abort(204) abort(204)
@@ -47,6 +45,5 @@ def yield_or_stop(generator):
yield next(generator) yield next(generator)
except StopIteration: except StopIteration:
raise raise
except (ExperimentalDisabledError, EmptyResponseError, except (EmptyResponseError, ConnectionError, HTTPError):
ConnectionError, HTTPError):
raise StopIteration raise StopIteration