Travis ci integration (#267)
* Initial travis-ci integration * Format code base to PEP8
This commit is contained in:
committed by
Corey Hammerton
parent
0ac64530bf
commit
faac5fa1bc
3
.coveragerc
Normal file
3
.coveragerc
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[report]
|
||||||
|
exclude_lines =
|
||||||
|
pragma: notest
|
||||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -1,5 +1,8 @@
|
|||||||
*.py[cod]
|
*.py[cod]
|
||||||
|
|
||||||
|
# Editor tmp files
|
||||||
|
.*.sw*
|
||||||
|
|
||||||
# C extensions
|
# C extensions
|
||||||
*.so
|
*.so
|
||||||
|
|
||||||
@@ -22,6 +25,7 @@ lib64
|
|||||||
pip-log.txt
|
pip-log.txt
|
||||||
|
|
||||||
# Unit test / coverage reports
|
# Unit test / coverage reports
|
||||||
|
.cache
|
||||||
.coverage
|
.coverage
|
||||||
.tox
|
.tox
|
||||||
nosetests.xml
|
nosetests.xml
|
||||||
@@ -36,3 +40,6 @@ nosetests.xml
|
|||||||
|
|
||||||
# PuppetDB Settings
|
# PuppetDB Settings
|
||||||
/settings.py
|
/settings.py
|
||||||
|
|
||||||
|
# Virtual Environment
|
||||||
|
venv
|
||||||
|
|||||||
13
.travis.yml
Normal file
13
.travis.yml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
language: python
|
||||||
|
|
||||||
|
python:
|
||||||
|
- "2.6"
|
||||||
|
- "2.7"
|
||||||
|
install:
|
||||||
|
- pip install -r requirements.txt
|
||||||
|
- pip install -r requirements-test.txt
|
||||||
|
- pip install -q coverage coveralls --use-wheel
|
||||||
|
script: py.test --cov=puppetboard --pep8 -v
|
||||||
|
|
||||||
|
after_success:
|
||||||
|
- coveralls
|
||||||
2
conftest.py
Normal file
2
conftest.py
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
import puppetboard
|
||||||
|
import test
|
||||||
4
dev.py
4
dev.py
@@ -20,12 +20,12 @@ if __name__ == '__main__':
|
|||||||
app.config['DEV_COFFEE_LOCATION'], '-w', '-c',
|
app.config['DEV_COFFEE_LOCATION'], '-w', '-c',
|
||||||
'-o', 'puppetboard/static/js',
|
'-o', 'puppetboard/static/js',
|
||||||
'puppetboard/static/coffeescript'
|
'puppetboard/static/coffeescript'
|
||||||
])
|
])
|
||||||
except OSError:
|
except OSError:
|
||||||
app.logger.error(
|
app.logger.error(
|
||||||
'The coffee executable was not found, disabling automatic '
|
'The coffee executable was not found, disabling automatic '
|
||||||
'CoffeeScript compilation'
|
'CoffeeScript compilation'
|
||||||
)
|
)
|
||||||
|
|
||||||
# Start the Flask development server
|
# Start the Flask development server
|
||||||
app.debug = True
|
app.debug = True
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ from flask import (
|
|||||||
Flask, render_template, abort, url_for,
|
Flask, render_template, abort, url_for,
|
||||||
Response, stream_with_context, redirect,
|
Response, stream_with_context, redirect,
|
||||||
request, session
|
request, session
|
||||||
)
|
)
|
||||||
|
|
||||||
from pypuppetdb import connect
|
from pypuppetdb import connect
|
||||||
from pypuppetdb.QueryBuilder import *
|
from pypuppetdb.QueryBuilder import *
|
||||||
@@ -23,8 +23,9 @@ from puppetboard.forms import (CatalogForm, QueryForm)
|
|||||||
from puppetboard.utils import (
|
from puppetboard.utils import (
|
||||||
get_or_abort, yield_or_stop,
|
get_or_abort, yield_or_stop,
|
||||||
jsonprint, prettyprint, Pagination
|
jsonprint, prettyprint, Pagination
|
||||||
)
|
)
|
||||||
|
|
||||||
|
DEFAULT_ORDER_BY = '[{"field": "start_time", "order": "desc"}]'
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
@@ -59,12 +60,14 @@ def stream_template(template_name, **context):
|
|||||||
rv.enable_buffering(5)
|
rv.enable_buffering(5)
|
||||||
return rv
|
return rv
|
||||||
|
|
||||||
|
|
||||||
def url_for_field(field, value):
|
def url_for_field(field, value):
|
||||||
args = request.view_args.copy()
|
args = request.view_args.copy()
|
||||||
args.update(request.args.copy())
|
args.update(request.args.copy())
|
||||||
args[field] = value
|
args[field] = value
|
||||||
return url_for(request.endpoint, **args)
|
return url_for(request.endpoint, **args)
|
||||||
|
|
||||||
|
|
||||||
def environments():
|
def environments():
|
||||||
envs = get_or_abort(puppetdb.environments)
|
envs = get_or_abort(puppetdb.environments)
|
||||||
x = []
|
x = []
|
||||||
@@ -74,12 +77,14 @@ def environments():
|
|||||||
|
|
||||||
return x
|
return x
|
||||||
|
|
||||||
|
|
||||||
def check_env(env, envs):
|
def check_env(env, envs):
|
||||||
if env != '*' and env not in envs:
|
if env != '*' and env not in envs:
|
||||||
abort(404)
|
abort(404)
|
||||||
|
|
||||||
app.jinja_env.globals['url_for_field'] = url_for_field
|
app.jinja_env.globals['url_for_field'] = url_for_field
|
||||||
|
|
||||||
|
|
||||||
@app.context_processor
|
@app.context_processor
|
||||||
def utility_processor():
|
def utility_processor():
|
||||||
def now(format='%m/%d/%Y %H:%M:%S'):
|
def now(format='%m/%d/%Y %H:%M:%S'):
|
||||||
@@ -163,7 +168,7 @@ def index(env):
|
|||||||
num_nodes_query.add_query(query)
|
num_nodes_query.add_query(query)
|
||||||
|
|
||||||
if app.config['OVERVIEW_FILTER'] != None:
|
if app.config['OVERVIEW_FILTER'] != None:
|
||||||
query.add(app.config['OVERVIEW_FILTER'])
|
query.add(app.config['OVERVIEW_FILTER'])
|
||||||
|
|
||||||
num_resources_query = ExtractOperator()
|
num_resources_query = ExtractOperator()
|
||||||
num_resources_query.add_field(FunctionOperator('count'))
|
num_resources_query.add_field(FunctionOperator('count'))
|
||||||
@@ -186,9 +191,9 @@ def index(env):
|
|||||||
metrics['avg_resources_node'] = 0
|
metrics['avg_resources_node'] = 0
|
||||||
|
|
||||||
nodes = get_or_abort(puppetdb.nodes,
|
nodes = get_or_abort(puppetdb.nodes,
|
||||||
query=query,
|
query=query,
|
||||||
unreported=app.config['UNRESPONSIVE_HOURS'],
|
unreported=app.config['UNRESPONSIVE_HOURS'],
|
||||||
with_status=True)
|
with_status=True)
|
||||||
|
|
||||||
nodes_overview = []
|
nodes_overview = []
|
||||||
stats = {
|
stats = {
|
||||||
@@ -197,7 +202,7 @@ def index(env):
|
|||||||
'failed': 0,
|
'failed': 0,
|
||||||
'unreported': 0,
|
'unreported': 0,
|
||||||
'noop': 0
|
'noop': 0
|
||||||
}
|
}
|
||||||
|
|
||||||
for node in nodes:
|
for node in nodes:
|
||||||
if node.status == 'unreported':
|
if node.status == 'unreported':
|
||||||
@@ -221,7 +226,7 @@ def index(env):
|
|||||||
stats=stats,
|
stats=stats,
|
||||||
envs=envs,
|
envs=envs,
|
||||||
current_env=env
|
current_env=env
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/nodes', defaults={'env': app.config['DEFAULT_ENVIRONMENT']})
|
@app.route('/nodes', defaults={'env': app.config['DEFAULT_ENVIRONMENT']})
|
||||||
@@ -263,9 +268,9 @@ def nodes(env):
|
|||||||
nodes.append(node)
|
nodes.append(node)
|
||||||
return Response(stream_with_context(
|
return Response(stream_with_context(
|
||||||
stream_template('nodes.html',
|
stream_template('nodes.html',
|
||||||
nodes=nodes,
|
nodes=nodes,
|
||||||
envs=envs,
|
envs=envs,
|
||||||
current_env=env)))
|
current_env=env)))
|
||||||
|
|
||||||
|
|
||||||
@app.route('/inventory', defaults={'env': app.config['DEFAULT_ENVIRONMENT']})
|
@app.route('/inventory', defaults={'env': app.config['DEFAULT_ENVIRONMENT']})
|
||||||
@@ -286,28 +291,28 @@ def inventory(env):
|
|||||||
envs = environments()
|
envs = environments()
|
||||||
check_env(env, envs)
|
check_env(env, envs)
|
||||||
|
|
||||||
fact_desc = [] # a list of fact descriptions to go
|
fact_desc = [] # a list of fact descriptions to go
|
||||||
# in the table header
|
# in the table header
|
||||||
fact_names = [] # a list of inventory fact names
|
fact_names = [] # a list of inventory fact names
|
||||||
factvalues = {} # values of the facts for all the nodes
|
factvalues = {} # values of the facts for all the nodes
|
||||||
# indexed by node name and fact name
|
# indexed by node name and fact name
|
||||||
nodedata = {} # a dictionary containing list of inventoried
|
nodedata = {} # a dictionary containing list of inventoried
|
||||||
# facts indexed by node name
|
# facts indexed by node name
|
||||||
nodelist = set() # a set of node names
|
nodelist = set() # a set of node names
|
||||||
|
|
||||||
# load the list of items/facts we want in our inventory
|
# load the list of items/facts we want in our inventory
|
||||||
try:
|
try:
|
||||||
inv_facts = app.config['INVENTORY_FACTS']
|
inv_facts = app.config['INVENTORY_FACTS']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
inv_facts = [ ('Hostname' ,'fqdn' ),
|
inv_facts = [('Hostname', 'fqdn'),
|
||||||
('IP Address' ,'ipaddress' ),
|
('IP Address', 'ipaddress'),
|
||||||
('OS' ,'lsbdistdescription'),
|
('OS', 'lsbdistdescription'),
|
||||||
('Architecture' ,'hardwaremodel' ),
|
('Architecture', 'hardwaremodel'),
|
||||||
('Kernel Version','kernelrelease' ) ]
|
('Kernel Version', 'kernelrelease')]
|
||||||
|
|
||||||
# generate a list of descriptions and a list of fact names
|
# generate a list of descriptions and a list of fact names
|
||||||
# from the list of tuples inv_facts.
|
# from the list of tuples inv_facts.
|
||||||
for description,name in inv_facts:
|
for description, name in inv_facts:
|
||||||
fact_desc.append(description)
|
fact_desc.append(description)
|
||||||
fact_names.append(name)
|
fact_names.append(name)
|
||||||
|
|
||||||
@@ -325,7 +330,7 @@ def inventory(env):
|
|||||||
|
|
||||||
# convert the json in easy to access data structure
|
# convert the json in easy to access data structure
|
||||||
for fact in facts:
|
for fact in facts:
|
||||||
factvalues[fact.node,fact.name] = fact.value
|
factvalues[fact.node, fact.name] = fact.value
|
||||||
nodelist.add(fact.node)
|
nodelist.add(fact.node)
|
||||||
|
|
||||||
# generate the per-host data
|
# generate the per-host data
|
||||||
@@ -333,19 +338,20 @@ def inventory(env):
|
|||||||
nodedata[node] = []
|
nodedata[node] = []
|
||||||
for fact_name in fact_names:
|
for fact_name in fact_names:
|
||||||
try:
|
try:
|
||||||
nodedata[node].append(factvalues[node,fact_name])
|
nodedata[node].append(factvalues[node, fact_name])
|
||||||
except KeyError:
|
except KeyError:
|
||||||
nodedata[node].append("undef")
|
nodedata[node].append("undef")
|
||||||
|
|
||||||
return Response(stream_with_context(
|
return Response(stream_with_context(
|
||||||
stream_template('inventory.html',
|
stream_template('inventory.html',
|
||||||
nodedata=nodedata,
|
nodedata=nodedata,
|
||||||
fact_desc=fact_desc,
|
fact_desc=fact_desc,
|
||||||
envs=envs,
|
envs=envs,
|
||||||
current_env=env)))
|
current_env=env)))
|
||||||
|
|
||||||
|
|
||||||
@app.route('/node/<node_name>', defaults={'env': app.config['DEFAULT_ENVIRONMENT']})
|
@app.route('/node/<node_name>',
|
||||||
|
defaults={'env': app.config['DEFAULT_ENVIRONMENT']})
|
||||||
@app.route('/<env>/node/<node_name>')
|
@app.route('/<env>/node/<node_name>')
|
||||||
def node(env, node_name):
|
def node(env, node_name):
|
||||||
"""Display a dashboard for a node showing as much data as we have on that
|
"""Display a dashboard for a node showing as much data as we have on that
|
||||||
@@ -367,9 +373,9 @@ def node(env, node_name):
|
|||||||
node = get_or_abort(puppetdb.node, node_name)
|
node = get_or_abort(puppetdb.node, node_name)
|
||||||
facts = node.facts()
|
facts = node.facts()
|
||||||
reports = get_or_abort(puppetdb.reports,
|
reports = get_or_abort(puppetdb.reports,
|
||||||
query=query,
|
query=query,
|
||||||
limit=app.config['REPORTS_COUNT'],
|
limit=app.config['REPORTS_COUNT'],
|
||||||
order_by='[{"field": "start_time", "order": "desc"}]')
|
order_by=DEFAULT_ORDER_BY)
|
||||||
reports, reports_events = tee(reports)
|
reports, reports_events = tee(reports)
|
||||||
report_event_counts = {}
|
report_event_counts = {}
|
||||||
|
|
||||||
@@ -408,7 +414,8 @@ def node(env, node_name):
|
|||||||
current_env=env)
|
current_env=env)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/reports/', defaults={'env': app.config['DEFAULT_ENVIRONMENT'], 'page': 1})
|
@app.route('/reports/',
|
||||||
|
defaults={'env': app.config['DEFAULT_ENVIRONMENT'], 'page': 1})
|
||||||
@app.route('/<env>/reports/', defaults={'page': 1})
|
@app.route('/<env>/reports/', defaults={'page': 1})
|
||||||
@app.route('/<env>/reports/page/<int:page>')
|
@app.route('/<env>/reports/page/<int:page>')
|
||||||
def reports(env, page):
|
def reports(env, page):
|
||||||
@@ -435,17 +442,17 @@ def reports(env, page):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
paging_args = {'limit': int(limit)}
|
paging_args = {'limit': int(limit)}
|
||||||
paging_args['offset'] = int((page-1) * paging_args['limit'])
|
paging_args['offset'] = int((page - 1) * paging_args['limit'])
|
||||||
except ValueError:
|
except ValueError:
|
||||||
paging_args = {}
|
paging_args = {}
|
||||||
|
|
||||||
reports = get_or_abort(puppetdb.reports,
|
reports = get_or_abort(puppetdb.reports,
|
||||||
query=reports_query,
|
query=reports_query,
|
||||||
order_by='[{"field": "start_time", "order": "desc"}]',
|
order_by=DEFAULT_ORDER_BY,
|
||||||
**paging_args)
|
**paging_args)
|
||||||
total = get_or_abort(puppetdb._query,
|
total = get_or_abort(puppetdb._query,
|
||||||
'reports',
|
'reports',
|
||||||
query=total_query)
|
query=total_query)
|
||||||
total = total[0]['count']
|
total = total[0]['count']
|
||||||
reports, reports_events = tee(reports)
|
reports, reports_events = tee(reports)
|
||||||
report_event_counts = {}
|
report_event_counts = {}
|
||||||
@@ -488,7 +495,8 @@ def reports(env, page):
|
|||||||
limit=paging_args.get('limit', total))))
|
limit=paging_args.get('limit', total))))
|
||||||
|
|
||||||
|
|
||||||
@app.route('/reports/<node_name>/', defaults={'env': app.config['DEFAULT_ENVIRONMENT'], 'page': 1})
|
@app.route('/reports/<node_name>/',
|
||||||
|
defaults={'env': app.config['DEFAULT_ENVIRONMENT'], 'page': 1})
|
||||||
@app.route('/<env>/reports/<node_name>', defaults={'page': 1})
|
@app.route('/<env>/reports/<node_name>', defaults={'page': 1})
|
||||||
@app.route('/<env>/reports/<node_name>/page/<int:page>')
|
@app.route('/<env>/reports/<node_name>/page/<int:page>')
|
||||||
def reports_node(env, node_name, page):
|
def reports_node(env, node_name, page):
|
||||||
@@ -517,13 +525,13 @@ def reports_node(env, node_name, page):
|
|||||||
total_query.add_query(query)
|
total_query.add_query(query)
|
||||||
|
|
||||||
reports = get_or_abort(puppetdb.reports,
|
reports = get_or_abort(puppetdb.reports,
|
||||||
query=query,
|
query=query,
|
||||||
limit=app.config['REPORTS_COUNT'],
|
limit=app.config['REPORTS_COUNT'],
|
||||||
offset=(page-1) * app.config['REPORTS_COUNT'],
|
offset=(page - 1) * app.config['REPORTS_COUNT'],
|
||||||
order_by='[{"field": "start_time", "order": "desc"}]')
|
order_by=DEFAULT_ORDER_BY)
|
||||||
total = get_or_abort(puppetdb._query,
|
total = get_or_abort(puppetdb._query,
|
||||||
'reports',
|
'reports',
|
||||||
query=total_query)
|
query=total_query)
|
||||||
total = total[0]['count']
|
total = total[0]['count']
|
||||||
reports, reports_events = tee(reports)
|
reports, reports_events = tee(reports)
|
||||||
report_event_counts = {}
|
report_event_counts = {}
|
||||||
@@ -565,7 +573,8 @@ def reports_node(env, node_name, page):
|
|||||||
current_env=env)
|
current_env=env)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/report/<node_name>/<report_id>', defaults={'env': app.config['DEFAULT_ENVIRONMENT']})
|
@app.route('/report/<node_name>/<report_id>',
|
||||||
|
defaults={'env': app.config['DEFAULT_ENVIRONMENT']})
|
||||||
@app.route('/<env>/report/<node_name>/<report_id>')
|
@app.route('/<env>/report/<node_name>/<report_id>')
|
||||||
def report(env, node_name, report_id):
|
def report(env, node_name, report_id):
|
||||||
"""Displays a single report including all the events associated with that
|
"""Displays a single report including all the events associated with that
|
||||||
@@ -637,10 +646,11 @@ def facts(env):
|
|||||||
|
|
||||||
sorted_facts_dict = sorted(facts_dict.items())
|
sorted_facts_dict = sorted(facts_dict.items())
|
||||||
return render_template('facts.html',
|
return render_template('facts.html',
|
||||||
facts_dict=sorted_facts_dict,
|
facts_dict=sorted_facts_dict,
|
||||||
facts_len=sum(map(len,facts_dict.values())) + len(facts_dict)*5,
|
facts_len=(sum(map(len, facts_dict.values())) +
|
||||||
envs=envs,
|
len(facts_dict) * 5),
|
||||||
current_env=env)
|
envs=envs,
|
||||||
|
current_env=env)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/fact/<fact>', defaults={'env': app.config['DEFAULT_ENVIRONMENT']})
|
@app.route('/fact/<fact>', defaults={'env': app.config['DEFAULT_ENVIRONMENT']})
|
||||||
@@ -679,7 +689,8 @@ def fact(env, fact):
|
|||||||
current_env=env)))
|
current_env=env)))
|
||||||
|
|
||||||
|
|
||||||
@app.route('/fact/<fact>/<value>', defaults={'env': app.config['DEFAULT_ENVIRONMENT']})
|
@app.route('/fact/<fact>/<value>',
|
||||||
|
defaults={'env': app.config['DEFAULT_ENVIRONMENT']})
|
||||||
@app.route('/<env>/fact/<fact>/<value>')
|
@app.route('/<env>/fact/<fact>/<value>')
|
||||||
def fact_value(env, fact, value):
|
def fact_value(env, fact, value):
|
||||||
"""On asking for fact/value get all nodes with that fact.
|
"""On asking for fact/value get all nodes with that fact.
|
||||||
@@ -700,9 +711,9 @@ def fact_value(env, fact, value):
|
|||||||
query = EqualsOperator("environment", env)
|
query = EqualsOperator("environment", env)
|
||||||
|
|
||||||
facts = get_or_abort(puppetdb.facts,
|
facts = get_or_abort(puppetdb.facts,
|
||||||
name=fact,
|
name=fact,
|
||||||
value=value,
|
value=value,
|
||||||
query=query)
|
query=query)
|
||||||
localfacts = [f for f in yield_or_stop(facts)]
|
localfacts = [f for f in yield_or_stop(facts)]
|
||||||
return render_template(
|
return render_template(
|
||||||
'fact.html',
|
'fact.html',
|
||||||
@@ -713,7 +724,8 @@ def fact_value(env, fact, value):
|
|||||||
current_env=env)
|
current_env=env)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/query', methods=('GET', 'POST'), defaults={'env': app.config['DEFAULT_ENVIRONMENT']})
|
@app.route('/query', methods=('GET', 'POST'),
|
||||||
|
defaults={'env': app.config['DEFAULT_ENVIRONMENT']})
|
||||||
@app.route('/<env>/query', methods=('GET', 'POST'))
|
@app.route('/<env>/query', methods=('GET', 'POST'))
|
||||||
def query(env):
|
def query(env):
|
||||||
"""Allows to execute raw, user created querries against PuppetDB. This is
|
"""Allows to execute raw, user created querries against PuppetDB. This is
|
||||||
@@ -745,14 +757,14 @@ def query(env):
|
|||||||
form.endpoints.data,
|
form.endpoints.data,
|
||||||
query=query)
|
query=query)
|
||||||
return render_template('query.html',
|
return render_template('query.html',
|
||||||
form=form,
|
form=form,
|
||||||
result=result,
|
result=result,
|
||||||
envs=envs,
|
envs=envs,
|
||||||
current_env=env)
|
current_env=env)
|
||||||
return render_template('query.html',
|
return render_template('query.html',
|
||||||
form=form,
|
form=form,
|
||||||
envs=envs,
|
envs=envs,
|
||||||
current_env=env)
|
current_env=env)
|
||||||
else:
|
else:
|
||||||
log.warn('Access to query interface disabled by administrator..')
|
log.warn('Access to query interface disabled by administrator..')
|
||||||
abort(403)
|
abort(403)
|
||||||
@@ -772,12 +784,13 @@ def metrics(env):
|
|||||||
|
|
||||||
metrics = get_or_abort(puppetdb._query, 'mbean')
|
metrics = get_or_abort(puppetdb._query, 'mbean')
|
||||||
return render_template('metrics.html',
|
return render_template('metrics.html',
|
||||||
metrics=sorted(metrics.keys()),
|
metrics=sorted(metrics.keys()),
|
||||||
envs=envs,
|
envs=envs,
|
||||||
current_env=env)
|
current_env=env)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/metric/<metric>', defaults={'env': app.config['DEFAULT_ENVIRONMENT']})
|
@app.route('/metric/<metric>',
|
||||||
|
defaults={'env': app.config['DEFAULT_ENVIRONMENT']})
|
||||||
@app.route('/<env>/metric/<metric>')
|
@app.route('/<env>/metric/<metric>')
|
||||||
def metric(env, metric):
|
def metric(env, metric):
|
||||||
"""Lists all information about the metric of the given name.
|
"""Lists all information about the metric of the given name.
|
||||||
@@ -798,6 +811,7 @@ def metric(env, metric):
|
|||||||
envs=envs,
|
envs=envs,
|
||||||
current_env=env)
|
current_env=env)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/catalogs', defaults={'env': app.config['DEFAULT_ENVIRONMENT']})
|
@app.route('/catalogs', defaults={'env': app.config['DEFAULT_ENVIRONMENT']})
|
||||||
@app.route('/<env>/catalogs')
|
@app.route('/<env>/catalogs')
|
||||||
def catalogs(env):
|
def catalogs(env):
|
||||||
@@ -819,10 +833,11 @@ def catalogs(env):
|
|||||||
|
|
||||||
query.add(NullOperator("catalog_timestamp", False))
|
query.add(NullOperator("catalog_timestamp", False))
|
||||||
|
|
||||||
|
order_by_str = '[{"field": "certname", "order": "asc"}]'
|
||||||
nodes = get_or_abort(puppetdb.nodes,
|
nodes = get_or_abort(puppetdb.nodes,
|
||||||
query=query,
|
query=query,
|
||||||
with_status=False,
|
with_status=False,
|
||||||
order_by='[{"field": "certname", "order": "asc"}]')
|
order_by=oder_by_str)
|
||||||
nodes, temp = tee(nodes)
|
nodes, temp = tee(nodes)
|
||||||
|
|
||||||
for node in temp:
|
for node in temp:
|
||||||
@@ -855,7 +870,9 @@ def catalogs(env):
|
|||||||
log.warn('Access to catalog interface disabled by administrator')
|
log.warn('Access to catalog interface disabled by administrator')
|
||||||
abort(403)
|
abort(403)
|
||||||
|
|
||||||
@app.route('/catalog/<node_name>', defaults={'env': app.config['DEFAULT_ENVIRONMENT']})
|
|
||||||
|
@app.route('/catalog/<node_name>',
|
||||||
|
defaults={'env': app.config['DEFAULT_ENVIRONMENT']})
|
||||||
@app.route('/<env>/catalog/<node_name>')
|
@app.route('/<env>/catalog/<node_name>')
|
||||||
def catalog_node(env, node_name):
|
def catalog_node(env, node_name):
|
||||||
"""Fetches from PuppetDB the compiled catalog of a given node.
|
"""Fetches from PuppetDB the compiled catalog of a given node.
|
||||||
@@ -868,16 +885,18 @@ def catalog_node(env, node_name):
|
|||||||
|
|
||||||
if app.config['ENABLE_CATALOG']:
|
if app.config['ENABLE_CATALOG']:
|
||||||
catalog = get_or_abort(puppetdb.catalog,
|
catalog = get_or_abort(puppetdb.catalog,
|
||||||
node=node_name)
|
node=node_name)
|
||||||
return render_template('catalog.html',
|
return render_template('catalog.html',
|
||||||
catalog=catalog,
|
catalog=catalog,
|
||||||
envs=envs,
|
envs=envs,
|
||||||
current_env=env)
|
current_env=env)
|
||||||
else:
|
else:
|
||||||
log.warn('Access to catalog interface disabled by administrator')
|
log.warn('Access to catalog interface disabled by administrator')
|
||||||
abort(403)
|
abort(403)
|
||||||
|
|
||||||
@app.route('/catalog/submit', methods=['POST'], defaults={'env': app.config['DEFAULT_ENVIRONMENT']})
|
|
||||||
|
@app.route('/catalog/submit', methods=['POST'],
|
||||||
|
defaults={'env': app.config['DEFAULT_ENVIRONMENT']})
|
||||||
@app.route('/<env>/catalog/submit', methods=['POST'])
|
@app.route('/<env>/catalog/submit', methods=['POST'])
|
||||||
def catalog_submit(env):
|
def catalog_submit(env):
|
||||||
"""Receives the submitted form data from the catalogs page and directs
|
"""Receives the submitted form data from the catalogs page and directs
|
||||||
@@ -901,15 +920,17 @@ def catalog_submit(env):
|
|||||||
against = form.against.data
|
against = form.against.data
|
||||||
return redirect(
|
return redirect(
|
||||||
url_for('catalog_compare',
|
url_for('catalog_compare',
|
||||||
env=env,
|
env=env,
|
||||||
compare=compare,
|
compare=compare,
|
||||||
against=against))
|
against=against))
|
||||||
return redirect(url_for('catalogs', env=env))
|
return redirect(url_for('catalogs', env=env))
|
||||||
else:
|
else:
|
||||||
log.warn('Access to catalog interface disabled by administrator')
|
log.warn('Access to catalog interface disabled by administrator')
|
||||||
abort(403)
|
abort(403)
|
||||||
|
|
||||||
@app.route('/catalogs/compare/<compare>...<against>', defaults={'env': app.config['DEFAULT_ENVIRONMENT']})
|
|
||||||
|
@app.route('/catalogs/compare/<compare>...<against>',
|
||||||
|
defaults={'env': app.config['DEFAULT_ENVIRONMENT']})
|
||||||
@app.route('/<env>/catalogs/compare/<compare>...<against>')
|
@app.route('/<env>/catalogs/compare/<compare>...<against>')
|
||||||
def catalog_compare(env, compare, against):
|
def catalog_compare(env, compare, against):
|
||||||
"""Compares the catalog of one node, parameter compare, with that of
|
"""Compares the catalog of one node, parameter compare, with that of
|
||||||
@@ -923,19 +944,20 @@ def catalog_compare(env, compare, against):
|
|||||||
|
|
||||||
if app.config['ENABLE_CATALOG']:
|
if app.config['ENABLE_CATALOG']:
|
||||||
compare_cat = get_or_abort(puppetdb.catalog,
|
compare_cat = get_or_abort(puppetdb.catalog,
|
||||||
node=compare)
|
node=compare)
|
||||||
against_cat = get_or_abort(puppetdb.catalog,
|
against_cat = get_or_abort(puppetdb.catalog,
|
||||||
node=against)
|
node=against)
|
||||||
|
|
||||||
return render_template('catalog_compare.html',
|
return render_template('catalog_compare.html',
|
||||||
compare=compare_cat,
|
compare=compare_cat,
|
||||||
against=against_cat,
|
against=against_cat,
|
||||||
envs=envs,
|
envs=envs,
|
||||||
current_env=env)
|
current_env=env)
|
||||||
else:
|
else:
|
||||||
log.warn('Access to catalog interface disabled by administrator')
|
log.warn('Access to catalog interface disabled by administrator')
|
||||||
abort(403)
|
abort(403)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/radiator', defaults={'env': app.config['DEFAULT_ENVIRONMENT']})
|
@app.route('/radiator', defaults={'env': app.config['DEFAULT_ENVIRONMENT']})
|
||||||
@app.route('/<env>/radiator')
|
@app.route('/<env>/radiator')
|
||||||
def radiator(env):
|
def radiator(env):
|
||||||
@@ -966,13 +988,11 @@ def radiator(env):
|
|||||||
query=metric_query)
|
query=metric_query)
|
||||||
num_nodes = metrics[0]['count']
|
num_nodes = metrics[0]['count']
|
||||||
|
|
||||||
|
|
||||||
nodes = puppetdb.nodes(
|
nodes = puppetdb.nodes(
|
||||||
query=query,
|
query=query,
|
||||||
unreported=app.config['UNRESPONSIVE_HOURS'],
|
unreported=app.config['UNRESPONSIVE_HOURS'],
|
||||||
with_status=True
|
with_status=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
stats = {
|
stats = {
|
||||||
'changed_percent': 0,
|
'changed_percent': 0,
|
||||||
@@ -989,8 +1009,6 @@ def radiator(env):
|
|||||||
'unreported': 0,
|
'unreported': 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for node in nodes:
|
for node in nodes:
|
||||||
if node.status == 'unreported':
|
if node.status == 'unreported':
|
||||||
stats['unreported'] += 1
|
stats['unreported'] += 1
|
||||||
@@ -1001,18 +1019,18 @@ def radiator(env):
|
|||||||
elif node.status == 'noop':
|
elif node.status == 'noop':
|
||||||
stats['noop'] += 1
|
stats['noop'] += 1
|
||||||
elif node.status == 'skipped':
|
elif node.status == 'skipped':
|
||||||
stats['skipped'] +=1
|
stats['skipped'] += 1
|
||||||
else:
|
else:
|
||||||
stats['unchanged'] += 1
|
stats['unchanged'] += 1
|
||||||
|
|
||||||
|
|
||||||
stats['changed_percent'] = int(100 * stats['changed'] / float(num_nodes))
|
stats['changed_percent'] = int(100 * stats['changed'] / float(num_nodes))
|
||||||
stats['failed_percent'] = int(100 * stats['failed'] / float(num_nodes))
|
stats['failed_percent'] = int(100 * stats['failed'] / float(num_nodes))
|
||||||
stats['noop_percent'] = int(100 * stats['noop'] / float(num_nodes))
|
stats['noop_percent'] = int(100 * stats['noop'] / float(num_nodes))
|
||||||
stats['skipped_percent'] = int(100 * stats['skipped'] / float(num_nodes))
|
stats['skipped_percent'] = int(100 * stats['skipped'] / float(num_nodes))
|
||||||
stats['unchanged_percent'] = int(100 * stats['unchanged'] / float(num_nodes))
|
stats['unchanged_percent'] = int(100 * (stats['unchanged'] /
|
||||||
stats['unreported_percent'] = int(100 * stats['unreported'] / float(num_nodes))
|
float(num_nodes)))
|
||||||
|
stats['unreported_percent'] = int(100 * (stats['unreported'] /
|
||||||
|
float(num_nodes)))
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
'radiator.html',
|
'radiator.html',
|
||||||
|
|||||||
@@ -31,10 +31,10 @@ GRAPH_FACTS = ['architecture',
|
|||||||
'osfamily',
|
'osfamily',
|
||||||
'puppetversion',
|
'puppetversion',
|
||||||
'processorcount']
|
'processorcount']
|
||||||
INVENTORY_FACTS = [ ('Hostname', 'fqdn' ),
|
INVENTORY_FACTS = [('Hostname', 'fqdn'),
|
||||||
('IP Address', 'ipaddress' ),
|
('IP Address', 'ipaddress'),
|
||||||
('OS', 'lsbdistdescription'),
|
('OS', 'lsbdistdescription'),
|
||||||
('Architecture', 'hardwaremodel' ),
|
('Architecture', 'hardwaremodel'),
|
||||||
('Kernel Version', 'kernelrelease' ),
|
('Kernel Version', 'kernelrelease'),
|
||||||
('Puppet Version', 'puppetversion' ), ]
|
('Puppet Version', 'puppetversion'), ]
|
||||||
REFRESH_RATE = 30
|
REFRESH_RATE = 30
|
||||||
|
|||||||
@@ -26,9 +26,10 @@ class QueryForm(Form):
|
|||||||
('edges', 'Edges'),
|
('edges', 'Edges'),
|
||||||
('environments', 'Environments'),
|
('environments', 'Environments'),
|
||||||
('pql', 'PQL'),
|
('pql', 'PQL'),
|
||||||
])
|
])
|
||||||
rawjson = BooleanField('Raw JSON')
|
rawjson = BooleanField('Raw JSON')
|
||||||
|
|
||||||
|
|
||||||
class CatalogForm(Form):
|
class CatalogForm(Form):
|
||||||
"""The form used to compare the catalogs of different nodes."""
|
"""The form used to compare the catalogs of different nodes."""
|
||||||
compare = HiddenField('compare')
|
compare = HiddenField('compare')
|
||||||
|
|||||||
@@ -19,40 +19,44 @@ except NameError:
|
|||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def jsonprint(value):
|
def jsonprint(value):
|
||||||
return json.dumps(value, indent=2, separators=(',', ': '))
|
return json.dumps(value, indent=2, separators=(',', ': '))
|
||||||
|
|
||||||
|
|
||||||
def formatvalue(value):
|
def formatvalue(value):
|
||||||
if isinstance(value, str):
|
if isinstance(value, str):
|
||||||
return value
|
return value
|
||||||
elif isinstance(value, list):
|
elif isinstance(value, list):
|
||||||
return ", ".join(value)
|
return ", ".join(value)
|
||||||
elif isinstance(value, dict):
|
elif isinstance(value, dict):
|
||||||
ret = ""
|
ret = ""
|
||||||
for k in value:
|
for k in value:
|
||||||
ret += k+" => "+formatvalue(value[k])+",<br/>"
|
ret += k + " => " + formatvalue(value[k]) + ",<br/>"
|
||||||
return ret
|
return ret
|
||||||
else:
|
else:
|
||||||
return str(value)
|
return str(value)
|
||||||
|
|
||||||
|
|
||||||
def prettyprint(value):
|
def prettyprint(value):
|
||||||
html = '<table class="ui basic fixed sortable table"><thead><tr>'
|
html = '<table class="ui basic fixed sortable table"><thead><tr>'
|
||||||
|
|
||||||
# Get keys
|
# Get keys
|
||||||
for k in value[0]:
|
for k in value[0]:
|
||||||
html += "<th>"+k+"</th>"
|
html += "<th>" + k + "</th>"
|
||||||
|
|
||||||
html += "</tr></thead><tbody>"
|
html += "</tr></thead><tbody>"
|
||||||
|
|
||||||
for e in value:
|
for e in value:
|
||||||
html += "<tr>"
|
html += "<tr>"
|
||||||
for k in e:
|
for k in e:
|
||||||
html += "<td>"+formatvalue(e[k])+"</td>"
|
html += "<td>" + formatvalue(e[k]) + "</td>"
|
||||||
html += "</tr>"
|
html += "</tr>"
|
||||||
|
|
||||||
html += "</tbody></table>"
|
html += "</tbody></table>"
|
||||||
return(html)
|
return(html)
|
||||||
|
|
||||||
|
|
||||||
def get_or_abort(func, *args, **kwargs):
|
def get_or_abort(func, *args, **kwargs):
|
||||||
"""Execute the function with its arguments and handle the possible
|
"""Execute the function with its arguments and handle the possible
|
||||||
errors that might occur.
|
errors that might occur.
|
||||||
@@ -87,6 +91,7 @@ def yield_or_stop(generator):
|
|||||||
except (EmptyResponseError, ConnectionError, HTTPError):
|
except (EmptyResponseError, ConnectionError, HTTPError):
|
||||||
raise StopIteration
|
raise StopIteration
|
||||||
|
|
||||||
|
|
||||||
class Pagination(object):
|
class Pagination(object):
|
||||||
|
|
||||||
def __init__(self, page, per_page, total_count):
|
def __init__(self, page, per_page, total_count):
|
||||||
@@ -111,9 +116,9 @@ class Pagination(object):
|
|||||||
last = 0
|
last = 0
|
||||||
for num in xrange(1, self.pages + 1):
|
for num in xrange(1, self.pages + 1):
|
||||||
if num <= left_edge or \
|
if num <= left_edge or \
|
||||||
(num > self.page - left_current - 1 and \
|
(num > self.page - left_current - 1 and
|
||||||
num < self.page + right_current) or \
|
num < self.page + right_current) or \
|
||||||
num > self.pages - right_edge:
|
num > self.pages - right_edge:
|
||||||
if last + 1 != num:
|
if last + 1 != num:
|
||||||
yield None
|
yield None
|
||||||
yield num
|
yield num
|
||||||
|
|||||||
6
requirements-test.txt
Normal file
6
requirements-test.txt
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
pep8==1.6.2
|
||||||
|
coverage==4.0
|
||||||
|
mock==1.3.0
|
||||||
|
pytest-pep8==1.0.5
|
||||||
|
pytest-cov==2.2.1
|
||||||
|
cov-core==1.15.0
|
||||||
17
setup.cfg
17
setup.cfg
@@ -6,3 +6,20 @@ build_requires = python-setuptools
|
|||||||
requires = python-flask
|
requires = python-flask
|
||||||
python-flask-wtf
|
python-flask-wtf
|
||||||
python-pypuppetdb
|
python-pypuppetdb
|
||||||
|
[pep8]
|
||||||
|
max-line-length=100
|
||||||
|
exclude=venv,dist,build
|
||||||
|
ignore=E402
|
||||||
|
|
||||||
|
[nosetests]
|
||||||
|
with-coverage = 1
|
||||||
|
with-xunit = 1
|
||||||
|
cover-package = puppetboard
|
||||||
|
|
||||||
|
[flake8]
|
||||||
|
exclude=venv
|
||||||
|
|
||||||
|
[pytest]
|
||||||
|
addopts = --cov=puppetboard --cov-report=term-missing
|
||||||
|
norecursedirs = docs .tox venv
|
||||||
|
pep8ignore = E402
|
||||||
|
|||||||
4
setup.py
4
setup.py
@@ -33,7 +33,7 @@ setup(
|
|||||||
"Flask-WTF >= 0.12, <= 0.13",
|
"Flask-WTF >= 0.12, <= 0.13",
|
||||||
"WTForms >= 2.0, < 3.0",
|
"WTForms >= 2.0, < 3.0",
|
||||||
"pypuppetdb >= 0.3.0, < 0.4.0",
|
"pypuppetdb >= 0.3.0, < 0.4.0",
|
||||||
],
|
],
|
||||||
keywords="puppet puppetdb puppetboard",
|
keywords="puppet puppetdb puppetboard",
|
||||||
classifiers=[
|
classifiers=[
|
||||||
'Development Status :: 3 - Alpha',
|
'Development Status :: 3 - Alpha',
|
||||||
@@ -49,5 +49,5 @@ setup(
|
|||||||
'Programming Language :: Python :: 3',
|
'Programming Language :: Python :: 3',
|
||||||
'Programming Language :: Python :: 3.2',
|
'Programming Language :: Python :: 3.2',
|
||||||
'Programming Language :: Python :: 3.3',
|
'Programming Language :: Python :: 3.3',
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|||||||
19
test/test_app.py
Normal file
19
test/test_app.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import os
|
||||||
|
from puppetboard import app
|
||||||
|
import unittest
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
|
||||||
|
class AppTestCase(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_first_test(self):
|
||||||
|
self.assertTrue(True)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
Reference in New Issue
Block a user