diff --git a/db.py b/db.py index 9ae0d82f465dce55d9dc852763a281773c084414..3965fae7dda6d8604551b11cfa309f9a16d046ca 100644 --- a/db.py +++ b/db.py @@ -42,6 +42,9 @@ if config['DB_ENGINE'] == 'sqlite': params = [(p.replace(microsecond=0) if isinstance(p, datetime) else p) for p in params] return operation, params + def show(operation, host=None): + return {} + elif config['DB_ENGINE'] == 'mysql': import mysql.connector @@ -57,6 +60,29 @@ elif config['DB_ENGINE'] == 'mysql': params = [(p.replace(microsecond=0) if isinstance(p, datetime) else p) for p in params] return operation, params + def show(operation, host=config.get('MYSQL_HOST', None)): + if host: + db = mysql.connector.connect(user=config['MYSQL_USER'], password=config['MYSQL_PASSWD'], host=host, port=config.get('MYSQL_PORT', 3306)) + else: + db = mysql.connector.connect(user=config['MYSQL_USER'], password=config['MYSQL_PASSWD'], unix_socket=config.get('MYSQL_UNIX', None)) + cur = db.cursor() + cur.execute(operation) + rows = [] + try: + rows = cur.fetchall() + except mysql.connector.errors.InterfaceError as ie: + if ie.msg == 'No result set to fetch from.': + # no problem, we were just at the end of the result set + pass + else: + raise + res = {} + for row in rows: + res[row[0]] = row[1] + cur.close() + db.close() + return res + def query(operation, *params, delim="sep"): operation, params = fix_query(operation, params) cur = get_dbcursor() diff --git a/server.py b/server.py index 0f6902ee7c02e35cab9a890aef92747394f881d2..40630db76c9332104361c3a2e866545ce0341e24 100644 --- a/server.py +++ b/server.py @@ -70,7 +70,7 @@ app.jinja_env.globals['gitversion'] = { 'hash': output[1], 'longhash': output[0] if not config.get('SECRET_KEY', None): config['SECRET_KEY'] = os.urandom(24) -from db import query, modify, searchquery, ldapauth, ldapget +from db import query, modify, show, searchquery, ldapauth, ldapget mod_endpoints = [] @@ -617,7 +617,33 @@ def legacy(phpfile=None): return redirect(url_for('feed', handle=request.args.copy().popitem()[0]),code=302) print("Unknown legacy url:",request.url) return redirect(url_for('index'),code=302) - + +import json + +@app.route('/internal/dbstatus') +@register_navbar('DB-Status', icon='ok') +@mod_required +def dbstatus(): + hosts = set() + clusters = {} + status = {} + variables = {} + for host in config.get('MYSQL_DBSTATUS_HOSTS', [])+[config.get('MYSQL_HOST', None)]: + for _host in show('SHOW VARIABLES LIKE "wsrep_cluster_address"', host=host)['wsrep_cluster_address'][len('gcomm://'):].split(','): + hosts.add(_host) + for host in hosts: + try: + status[host] = show('SHOW GLOBAL STATUS LIKE "wsrep%"', host=host) + variables[host] = show('SHOW GLOBAL VARIABLES LIKE "wsrep%"', host=host) + except: + status[host] = {'wsrep_cluster_state_uuid': '', 'wsrep_local_state_comment': 'Not reachable', 'wsrep_cluster_conf_id': '0', 'wsrep_cluster_status': 'Unknown'} + variables[host] = {'wsrep_node_name': host, 'wsrep_cluster_name': 'unknown'} + cluster = variables[host]['wsrep_cluster_name']+'-'+status[host]['wsrep_cluster_conf_id'] + if cluster not in clusters: + clusters[cluster] = [] + clusters[cluster].append(host) + return render_template('dbstatus.html', clusters=clusters, statuses=status, vars=variables), 200 + import edit import feeds import importer diff --git a/templates/dbstatus.html b/templates/dbstatus.html new file mode 100644 index 0000000000000000000000000000000000000000..384e3a84446cd6003c08ae676d673cffb72281fc --- /dev/null +++ b/templates/dbstatus.html @@ -0,0 +1,53 @@ +{% extends "base.html" %} +{% block content %} +<div class="panel panel-default"> + <div class="panel-heading"><h1 class="panel-title">Cluster</b></h1></div> + <ul class="list-group"> + {% for clustername, clusternodes in clusters.items() %} + <li class="list-group-item"><strong>{{vars[clusternodes|first]['wsrep_cluster_name']}}</strong> ({{statuses[clusternodes|first]['wsrep_cluster_status']}}, Größe={{statuses[clusternodes|first]['wsrep_cluster_size']}}, Konfiguration={{statuses[clusternodes|first]['wsrep_cluster_conf_id']}}) + <ul class="list-group"> + {% for host in clusternodes %} + <li class="list-group-item list-group-item-{{{'1': 'warning', '2': 'warning', '3': 'info', '4': 'success'}.get(statuses[host]['wsrep_local_state'], 'danger')}}"><a href="#{{host|tagid}}">{{vars[host]['wsrep_node_name']}}</a> ({{statuses[host]['wsrep_local_state_comment']}}, Letzte Änderung={{statuses[host]['wsrep_last_committed']}}, Recv.-Avg.={{statuses[host]['wsrep_local_recv_queue_avg']}}, Send-Avg.={{statuses[host]['wsrep_local_send_queue_avg']}})</li> + {% endfor %} + </ul> + </li> + {% endfor %} + </ul> + </table> +</div> +{% for host, status in statuses.items() %} +<div class="panel panel-default" id="{{host|tagid}}"> + <div class="panel-heading"><h1 class="panel-title">{{vars[host]['wsrep_node_name']}}</h1></div> + <div class="row" style="margin: 0px;"> + <div class="col-xs-6 table-responsive"> + <table class="table"> + <tr> + <th>Variable</th> + <th>Wert</th> + </tr> + {% for key, value in vars[host].items() %} + <tr> + <td>{{key}}</td> + <td>{{value}}</td> + </tr> + {% endfor %} + </table> + </div> + <div class="col-xs-6 table-responsive"> + <table class="table"> + <tr> + <th>Status-Variable</th> + <th>Wert</th> + </tr> + {% for key, value in status.items() %} + <tr> + <td>{{key}}</td> + <td>{{value}}</td> + </tr> + {% endfor %} + </table> + </div> + </div> +</div> +{% endfor %} +{% endblock %}