Refactor out some global space to allow for testable code

and handling error conditions before flask is completely
initialized.
This commit is contained in:
Mike Terzo
2017-07-01 02:10:31 -04:00
parent df915834a4
commit 9488e8cb83
6 changed files with 155 additions and 87 deletions

View File

@@ -16,21 +16,22 @@ from flask import (
request, session, jsonify
)
from pypuppetdb import connect
from pypuppetdb.QueryBuilder import *
from puppetboard.forms import QueryForm
from puppetboard.utils import (
get_or_abort, yield_or_stop, get_db_version,
jsonprint, prettyprint
)
from puppetboard.utils import (get_or_abort, yield_or_stop,
get_db_version)
from puppetboard.dailychart import get_daily_reports_chart
import werkzeug.exceptions as ex
import CommonMark
from puppetboard.core import get_app, get_puppetdb, environments
import puppetboard.errors
from . import __version__
REPORTS_COLUMNS = [
{'attr': 'end', 'filter': 'end_time',
'name': 'End time', 'type': 'datetime'},
@@ -48,31 +49,15 @@ CATALOGS_COLUMNS = [
{'attr': 'form', 'name': 'Compare'},
]
app = Flask(__name__)
app.config.from_object('puppetboard.default_settings')
app = get_app()
graph_facts = app.config['GRAPH_FACTS']
app.config.from_envvar('PUPPETBOARD_SETTINGS', silent=True)
graph_facts += app.config['GRAPH_FACTS']
app.secret_key = app.config['SECRET_KEY']
app.jinja_env.filters['jsonprint'] = jsonprint
app.jinja_env.filters['prettyprint'] = prettyprint
puppetdb = connect(
host=app.config['PUPPETDB_HOST'],
port=app.config['PUPPETDB_PORT'],
ssl_verify=app.config['PUPPETDB_SSL_VERIFY'],
ssl_key=app.config['PUPPETDB_KEY'],
ssl_cert=app.config['PUPPETDB_CERT'],
timeout=app.config['PUPPETDB_TIMEOUT'],)
numeric_level = getattr(logging, app.config['LOGLEVEL'].upper(), None)
if not isinstance(numeric_level, int):
raise ValueError('Invalid log level: %s' % app.config['LOGLEVEL'])
logging.basicConfig(level=numeric_level)
log = logging.getLogger(__name__)
puppetdb = get_puppetdb()
@app.template_global()
def version():
@@ -87,29 +72,10 @@ def stream_template(template_name, **context):
return rv
def url_for_field(field, value):
args = request.view_args.copy()
args.update(request.args.copy())
args[field] = value
return url_for(request.endpoint, **args)
def environments():
envs = get_or_abort(puppetdb.environments)
x = []
for env in envs:
x.append(env['name'])
return x
def check_env(env, envs):
if env != '*' and env not in envs:
abort(404)
app.jinja_env.globals['url_for_field'] = url_for_field
@app.context_processor
def utility_processor():
@@ -119,38 +85,6 @@ def utility_processor():
return dict(now=now)
@app.errorhandler(400)
def bad_request(e):
envs = environments()
return render_template('400.html', envs=envs), 400
@app.errorhandler(403)
def forbidden(e):
envs = environments()
return render_template('403.html', envs=envs), 403
@app.errorhandler(404)
def not_found(e):
envs = environments()
return render_template('404.html', envs=envs), 404
@app.errorhandler(412)
def precond_failed(e):
"""We're slightly abusing 412 to handle missing features
depending on the API version."""
envs = environments()
return render_template('412.html', envs=envs), 412
@app.errorhandler(500)
def server_error(e):
envs = environments()
return render_template('500.html', envs=envs), 500
@app.route('/', defaults={'env': app.config['DEFAULT_ENVIRONMENT']})
@app.route('/<env>/')
def index(env):

63
puppetboard/core.py Normal file
View File

@@ -0,0 +1,63 @@
from __future__ import unicode_literals
from __future__ import absolute_import
import logging
from flask import Flask
from pypuppetdb import connect
from puppetboard.utils import (jsonprint, prettyprint, url_for_field,
get_or_abort)
from . import __version__
APP = None
PUPPETDB = None
def get_app():
global APP
if APP is None:
app = Flask(__name__)
app.config.from_object('puppetboard.default_settings')
app.config.from_envvar('PUPPETBOARD_SETTINGS', silent=True)
app.secret_key = app.config['SECRET_KEY']
numeric_level = getattr(logging, app.config['LOGLEVEL'].upper(), None)
if not isinstance(numeric_level, int):
raise ValueError('Invalid log level: %s' % app.config['LOGLEVEL'])
app.jinja_env.filters['jsonprint'] = jsonprint
app.jinja_env.filters['prettyprint'] = prettyprint
app.jinja_env.globals['url_for_field'] = url_for_field
APP = app
return APP
def get_puppetdb():
global PUPPETDB
if PUPPETDB is None:
app = get_app()
puppetdb = connect(host=app.config['PUPPETDB_HOST'],
port=app.config['PUPPETDB_PORT'],
ssl_verify=app.config['PUPPETDB_SSL_VERIFY'],
ssl_key=app.config['PUPPETDB_KEY'],
ssl_cert=app.config['PUPPETDB_CERT'],
timeout=app.config['PUPPETDB_TIMEOUT'],)
PUPPETDB = puppetdb
return PUPPETDB
def environments():
puppetdb = get_puppetdb()
envs = get_or_abort(puppetdb.environments)
x = []
for env in envs:
x.append(env['name'])
return x

45
puppetboard/errors.py Normal file
View File

@@ -0,0 +1,45 @@
from __future__ import unicode_literals
from __future__ import absolute_import
from puppetboard.core import get_app, environments
from werkzeug.exceptions import InternalServerError
from flask import render_template
from . import __version__
app = get_app()
@app.errorhandler(400)
def bad_request(e):
envs = environments()
return render_template('400.html', envs=envs), 400
@app.errorhandler(403)
def forbidden(e):
envs = environments()
return render_template('403.html', envs=envs), 403
@app.errorhandler(404)
def not_found(e):
envs = environments()
return render_template('404.html', envs=envs), 404
@app.errorhandler(412)
def precond_failed(e):
"""We're slightly abusing 412 to handle missing features
depending on the API version."""
envs = environments()
return render_template('412.html', envs=envs), 412
@app.errorhandler(500)
def server_error(e):
envs = []
try:
envs = environments()
except InternalServerError as e:
pass
return render_template('500.html', envs=envs), 500

View File

@@ -8,8 +8,7 @@ from math import ceil
from requests.exceptions import HTTPError, ConnectionError
from pypuppetdb.errors import EmptyResponseError
from flask import abort
from flask import abort, request, url_for
# Python 3 compatibility
try:
@@ -20,6 +19,13 @@ except NameError:
log = logging.getLogger(__name__)
def url_for_field(field, value):
args = request.view_args.copy()
args.update(request.args.copy())
args[field] = value
return url_for(request.endpoint, **args)
def jsonprint(value):
return json.dumps(value, indent=2, separators=(',', ': '))