diff --git a/puppetboard/app.py b/puppetboard/app.py index 9dfe18a..05ce75d 100644 --- a/puppetboard/app.py +++ b/puppetboard/app.py @@ -343,29 +343,11 @@ def nodes(env): current_env=env))) -@app.route('/inventory', defaults={'env': app.config['DEFAULT_ENVIRONMENT']}) -@app.route('//inventory') -def inventory(env): - """Fetch all (active) nodes from PuppetDB and stream a table displaying - those nodes along with a set of facts about them. - - Downside of the streaming aproach is that since we've already sent our - headers we can't abort the request if we detect an error. Because of this - we'll end up with an empty table instead because of how yield_or_stop - works. Once pagination is in place we can change this but we'll need to - provide a search feature instead. - - :param env: Search for facts in this environment - :type env: :obj:`string` - """ - envs = environments() - check_env(env, envs) - - headers = [] # a list of fact descriptions to go - # in the table header - fact_names = [] # a list of inventory fact names - fact_data = {} # a multidimensional dict for node and - # fact data +def inventory_facts(): + # a list of facts descriptions to go in table header + headers = [] + # a list of inventory fact names + fact_names = [] # load the list of items/facts we want in our inventory try: @@ -383,33 +365,65 @@ def inventory(env): headers.append(desc) fact_names.append(name) + return headers, fact_names + + +@app.route('/inventory', defaults={'env': app.config['DEFAULT_ENVIRONMENT']}) +@app.route('//inventory') +def inventory(env): + """Fetch all (active) nodes from PuppetDB and stream a table displaying + those nodes along with a set of facts about them. + + :param env: Search for facts in this environment + :type env: :obj:`string` + """ + envs = environments() + check_env(env, envs) + headers, fact_names = inventory_facts() + + return render_template( + 'inventory.html', + envs=envs, + current_env=env, + fact_headers=headers) + + +@app.route('/inventory/json', + defaults={'env': app.config['DEFAULT_ENVIRONMENT']}) +@app.route('//inventory/json') +def inventory_ajax(env): + """Backend endpoint for inventory table""" + draw = int(request.args.get('draw', 0)) + + envs = environments() + check_env(env, envs) + headers, fact_names = inventory_facts() + query = AndOperator() fact_query = OrOperator() fact_query.add([EqualsOperator("name", name) for name in fact_names]) + query.add(fact_query) if env != '*': query.add(EqualsOperator("environment", env)) - query.add(fact_query) - - # get all the facts from PuppetDB facts = puppetdb.facts(query=query) + fact_data = {} for fact in facts: if fact.node not in fact_data: fact_data[fact.node] = {} - fact_data[fact.node][fact.name] = fact.value - return Response(stream_with_context( - stream_template( - 'inventory.html', - headers=headers, - fact_names=fact_names, + total = len(fact_data) + + return render_template( + 'inventory.json.tpl', + draw=draw, + total=total, + total_filtered=total, fact_data=fact_data, - envs=envs, - current_env=env - ))) + columns=fact_names) @app.route('/node//', diff --git a/puppetboard/templates/inventory.html b/puppetboard/templates/inventory.html index 5eedeb7..098e1d8 100644 --- a/puppetboard/templates/inventory.html +++ b/puppetboard/templates/inventory.html @@ -1,24 +1,21 @@ {% extends 'layout.html' %} +{% import '_macros.html' as macros %} {% block content %} -
- -
- +
- {% for head in headers %} - {{head}} + {% for head in fact_headers %} + {% endfor %} - {% for node, facts in fact_data.iteritems() %} - - {% for name in fact_names %} - - {% endfor %} - - {% endfor %}
{{head}}
{{facts.get(name, 'undef')}}
{% endblock content %} +{% block onload_script %} +{% macro extra_options(caller) %} + 'serverSide': false, +{% endmacro %} +{{ macros.datatable_init(table_html_id="inventory_table", ajax_url=url_for('inventory_ajax', env=current_env), default_length=config.NORMAL_TABLE_COUNT, length_selector=config.TABLE_COUNT_SELECTOR, extra_options=extra_options) }} +{% endblock onload_script %} diff --git a/puppetboard/templates/inventory.json.tpl b/puppetboard/templates/inventory.json.tpl new file mode 100644 index 0000000..4d94bcd --- /dev/null +++ b/puppetboard/templates/inventory.json.tpl @@ -0,0 +1,23 @@ +{%- import '_macros.html' as macros -%} +{ + "draw": {{draw}}, + "recordsTotal": {{total}}, + "recordsFiltered": {{total_filtered}}, + "data": [ + {% for node in fact_data -%} + {%- if not loop.first %},{%- endif -%} + [ + {%- for column in columns -%} + {%- if not loop.first %},{%- endif -%} + {%- if column in ['fqdn', 'hostname'] -%} + {% filter jsonprint %}{{ node }}{% endfilter %} + {%- elif fact_data[node][column] -%} + {{ fact_data[node][column] | jsonprint }} + {%- else -%} + "" + {%- endif -%} + {%- endfor -%} + ] + {% endfor -%} + ] +}