diff --git a/puppetboard/app.py b/puppetboard/app.py index 615a3a1..147432a 100644 --- a/puppetboard/app.py +++ b/puppetboard/app.py @@ -391,9 +391,9 @@ def inventory(env): ))) -@app.route('/node//', +@app.route('/node/', defaults={'env': app.config['DEFAULT_ENVIRONMENT']}) -@app.route('//node//') +@app.route('//node/') def node(env, node_name): """Display a dashboard for a node showing as much data as we have on that node. This includes facts and reports but not Resources as that is too @@ -421,11 +421,11 @@ def node(env, node_name): columns=REPORTS_COLUMNS[:2]) -@app.route('/reports/', +@app.route('/reports', defaults={'env': app.config['DEFAULT_ENVIRONMENT'], 'node_name': None}) -@app.route('//reports/', defaults={'node_name': None}) -@app.route('/reports//', +@app.route('//reports', defaults={'node_name': None}) +@app.route('/reports/', defaults={'env': app.config['DEFAULT_ENVIRONMENT']}) @app.route('//reports/') def reports(env, node_name): diff --git a/puppetboard/templates/_macros.html b/puppetboard/templates/_macros.html index e3b31b1..0e4828d 100644 --- a/puppetboard/templates/_macros.html +++ b/puppetboard/templates/_macros.html @@ -1,51 +1,3 @@ -{% macro facts_table(facts, current_env, autofocus=False, condensed=False, show_node=False, show_value=True, link_facts=False, margin_top=20, margin_bottom=20) -%} -
- -
- - - - {% if show_node %} - - {% else %} - - {% endif %} - {% if show_value %} - - {% endif %} - - - - {% for fact in facts %} - - {% if show_node %} - - {% else %} - - {% endif %} - {% if show_value %} - - {% endif %} - - {% endfor %} - -
NodeFactValue
{{fact.node}}{{fact.name}} - {% if link_facts %} - {% if fact.value is mapping %} -
{{fact.value|jsonprint}}
- {% else %} - {{fact.value}} - {% endif %} - {% else %} - {% if fact.value is mapping %} -
{{fact.value|jsonprint}}
- {% else %} - {{fact.value}} - {% endif %} - {% endif %} -
-{%- endmacro %} - {% macro status_counts(caller, status, node_name, events, current_env, unreported_time=False, report_hash=False) -%} {{ status|upper }} {% if status == 'unreported' %} diff --git a/test/test_app.py b/test/test_app.py index 3b8f77a..357e5ba 100644 --- a/test/test_app.py +++ b/test/test_app.py @@ -582,7 +582,7 @@ def test_catalogs_json(client, mocker, found_status = None for status in ['failed', 'changed', 'unchanged', 'noop', 'unreported']: val = BeautifulSoup(line[0], 'html.parser').find_all( - 'a', {"href": "/node/node-%s/" % status}) + 'a', {"href": "/node/node-%s" % status}) if len(val) == 1: found_status = status break @@ -609,7 +609,7 @@ def test_catalogs_json_compare(client, mocker, found_status = None for status in ['failed', 'changed', 'unchanged', 'noop', 'unreported']: val = BeautifulSoup(line[0], 'html.parser').find_all( - 'a', {"href": "/node/node-%s/" % status}) + 'a', {"href": "/node/node-%s" % status}) if len(val) == 1: found_status = status break @@ -639,3 +639,185 @@ def test_facts_view(client, mocker, mock_puppetdb_environments): searchable = soup.find('div', {'class': 'searchable'}) vals = searchable.find_all('div', {'class': 'column'}) assert len(vals) == 4 + + +def test_fact_view_with_graph(client, mocker, + mock_puppetdb_environments, + mock_puppetdb_default_nodes): + rv = client.get('/fact/architecture') + assert rv.status_code == 200 + + soup = BeautifulSoup(rv.data, 'html.parser') + assert soup.title.contents[0] == 'Puppetboard' + + vals = soup.find_all('div', {"id": "factChart"}) + assert len(vals) == 1 + + +def test_fact_view_without_graph(client, mocker, + mock_puppetdb_environments, + mock_puppetdb_default_nodes): + rv = client.get('/%2A/fact/augeas') + assert rv.status_code == 200 + + soup = BeautifulSoup(rv.data, 'html.parser') + assert soup.title.contents[0] == 'Puppetboard' + + vals = soup.find_all('div', {"id": "factChart"}) + assert len(vals) == 0 + + +def test_fact_value_view(client, mocker, + mock_puppetdb_environments, + mock_puppetdb_default_nodes): + rv = client.get('/fact/architecture/amd64') + assert rv.status_code == 200 + + soup = BeautifulSoup(rv.data, 'html.parser') + assert soup.title.contents[0] == 'Puppetboard' + + vals = soup.find_all('div', {"id": "factChart"}) + assert len(vals) == 0 + + +def test_node_view(client, mocker, + mock_puppetdb_environments, + mock_puppetdb_default_nodes): + rv = client.get('/node/node-failed') + assert rv.status_code == 200 + + soup = BeautifulSoup(rv.data, 'html.parser') + assert soup.title.contents[0] == 'Puppetboard' + + vals = soup.find_all('table', {"id": "facts_table"}) + assert len(vals) == 1 + + vals = soup.find_all('table', {"id": "reports_table"}) + assert len(vals) == 1 + + +def test_fact_json_with_graph(client, mocker, + mock_puppetdb_environments, + mock_puppetdb_default_nodes): + values = ['a', 'b', 'b', 'd'] + query_data = {'facts': []} + query_data['facts'].append([]) + for i, value in enumerate(values): + query_data['facts'][0].append({ + 'certname': 'node-%s' % i, + 'name': 'architecture', + 'value': value, + 'environment': 'production' + }) + + dbquery = MockDbQuery(query_data) + + mocker.patch.object(app.puppetdb, '_query', side_effect=dbquery.get) + + rv = client.get('/fact/architecture/json') + assert rv.status_code == 200 + + result_json = json.loads(rv.data.decode('utf-8')) + + assert 'data' in result_json + assert len(result_json['data']) == 4 + for line in result_json['data']: + assert len(line) == 2 + + assert 'chart' in result_json + assert len(result_json['chart']) == 3 + # Test group_by + assert result_json['chart'][1]['value'] == 2 + + +def test_fact_json_without_graph(client, mocker, + mock_puppetdb_environments, + mock_puppetdb_default_nodes): + values = ['a', 'b', 'b', 'd'] + query_data = {'facts': []} + query_data['facts'].append([]) + for i, value in enumerate(values): + query_data['facts'][0].append({ + 'certname': 'node-%s' % i, + 'name': 'architecture', + 'value': value, + 'environment': 'production' + }) + + dbquery = MockDbQuery(query_data) + + mocker.patch.object(app.puppetdb, '_query', side_effect=dbquery.get) + + rv = client.get('/%2A/fact/augeas/json') + assert rv.status_code == 200 + + result_json = json.loads(rv.data.decode('utf-8')) + + assert 'data' in result_json + assert len(result_json['data']) == 4 + for line in result_json['data']: + assert len(line) == 2 + + assert 'chart' not in result_json + + +def test_fact_value_json(client, mocker, + mock_puppetdb_environments, + mock_puppetdb_default_nodes): + values = ['a', 'b', 'b', 'd'] + query_data = {'facts': []} + query_data['facts'].append([]) + for i, value in enumerate(values): + query_data['facts'][0].append({ + 'certname': 'node-%s' % i, + 'name': 'architecture', + 'value': value, + 'environment': 'production' + }) + + dbquery = MockDbQuery(query_data) + + mocker.patch.object(app.puppetdb, '_query', side_effect=dbquery.get) + + rv = client.get('/fact/architecture/amd64/json') + assert rv.status_code == 200 + + result_json = json.loads(rv.data.decode('utf-8')) + + assert 'data' in result_json + assert len(result_json['data']) == 4 + for line in result_json['data']: + assert len(line) == 1 + + assert 'chart' not in result_json + + +def test_node_facts_json(client, mocker, + mock_puppetdb_environments, + mock_puppetdb_default_nodes): + values = ['a', 'b', 'b', 'd'] + query_data = {'facts': []} + query_data['facts'].append([]) + for i, value in enumerate(values): + query_data['facts'][0].append({ + 'certname': 'node-failed', + 'name': 'fact-%s' % i, + 'value': value, + 'environment': 'production' + }) + + dbquery = MockDbQuery(query_data) + + mocker.patch.object(app.puppetdb, '_query', side_effect=dbquery.get) + + rv = client.get('/node/node-failed/facts/json') + assert rv.status_code == 200 + + result_json = json.loads(rv.data.decode('utf-8')) + + assert 'data' in result_json + assert len(result_json['data']) == 4 + for line in result_json['data']: + assert len(line) == 2 + + assert 'chart' not in result_json