Meet metrics! Now in HAProxy-WI you can see count incomning connections!
pull/30/head
Aidaho12 2018-08-04 01:17:03 +06:00
parent 08dc1d8146
commit a8c7b99db8
18 changed files with 455 additions and 52 deletions

View File

@ -29,6 +29,7 @@ Support the project
19. SYN flood protect 19. SYN flood protect
20. Alerting about changes backends state 20. Alerting about changes backends state
21. Alerting about HAProxy service state 21. Alerting about HAProxy service state
22. Metrics incoming connections
# Install # Install
The installer will ask you a few questions The installer will ask you a few questions

View File

@ -347,7 +347,7 @@ def update_db_v_2_6(**kwargs):
return True return True
cur.close() cur.close()
con.close() con.close()
def update_db_v_2_61(**kwargs): def update_db_v_2_61(**kwargs):
con, cur = get_cur() con, cur = get_cur()
sql = """ sql = """
@ -406,7 +406,7 @@ def update_db_v_2_7(**kwargs):
print("An error occurred:", e) print("An error occurred:", e)
return False return False
else: else:
print("DB was update to 2.7<br />") print("DB was update to 2.7.2<br />")
return True return True
cur.close() cur.close()
con.close() con.close()
@ -435,6 +435,63 @@ def update_db_v_2_7_2(**kwargs):
cur.close() cur.close()
con.close() con.close()
def update_db_v_2_8(**kwargs):
con, cur = get_cur()
sql = """CREATE TABLE IF NOT EXISTS `metrics` (`serv` varchar(64), curr_con INTEGER, cur_ssl_con INTEGER, sess_rate INTEGER, max_sess_rate INTEGER,`date` DATETIME default '0000-00-00 00:00:00'); """
try:
cur.execute(sql)
con.commit()
except sqltool.Error as e:
if kwargs.get('silent') != 1:
if e.args[0] == 'duplicate column name: token' or e == "1060 (42S21): Duplicate column name 'token' ":
print('Updating... go to version 2.6')
else:
print("An error occurred:", e.args[0])
return False
else:
print("DB was update to 2.8<br />")
return True
cur.close()
con.close()
def update_db_v_2_8(**kwargs):
con, cur = get_cur()
sql = """CREATE TABLE IF NOT EXISTS `metrics` (`serv` varchar(64), curr_con INTEGER, cur_ssl_con INTEGER, sess_rate INTEGER, max_sess_rate INTEGER,`date` DATETIME default '0000-00-00 00:00:00'); """
try:
cur.execute(sql)
con.commit()
except sqltool.Error as e:
if kwargs.get('silent') != 1:
if e.args[0] == 'duplicate column name: token' or e == "1060 (42S21): Duplicate column name 'token' ":
print('Updating... go to version 2.6')
else:
print("An error occurred:", e.args[0])
return False
else:
print("DB was update to 2.8<br />")
return True
cur.close()
con.close()
def update_db_v_2_8_2(**kwargs):
con, cur = get_cur()
sql = """ ALTER TABLE `servers` ADD COLUMN metrics INTEGER NOT NULL DEFAULT 0 """
try:
cur.execute(sql)
con.commit()
except sqltool.Error as e:
if kwargs.get('silent') != 1:
if e.args[0] == 'duplicate column name: metrics' or e == "1060 (42S21): Duplicate column name 'metrics' ":
print('DB was update to 2.8. It\' last version')
else:
print("An error occurred:", e.args[0])
return False
else:
print("DB was update to 2.8<br />")
return True
cur.close()
con.close()
def update_all(): def update_all():
update_db_v_2_0_1() update_db_v_2_0_1()
update_db_v_2_0_1_1() update_db_v_2_0_1_1()
@ -447,6 +504,8 @@ def update_all():
update_db_v_2_6_1() update_db_v_2_6_1()
update_db_v_2_7() update_db_v_2_7()
update_db_v_2_7_2() update_db_v_2_7_2()
update_db_v_2_8()
update_db_v_2_8_2()
def update_all_silent(): def update_all_silent():
update_db_v_2_0_1(silent=1) update_db_v_2_0_1(silent=1)
@ -460,4 +519,6 @@ def update_all_silent():
update_db_v_2_6_1(silent=1) update_db_v_2_6_1(silent=1)
update_db_v_2_7(silent=1) update_db_v_2_7(silent=1)
update_db_v_2_7_2(silent=1) update_db_v_2_7_2(silent=1)
update_db_v_2_8(silent=1)
update_db_v_2_8_2(silent=1)

View File

@ -57,12 +57,15 @@ def logging(serv, action, **kwargs):
except: except:
pass pass
if kwargs.get('alerting') != 1: if kwargs.get('alerting') == 1:
mess = get_data('date_in_log') + " from " + IP + " user: " + login + " " + action + " for: " + serv + "\n"
log = open(log_path + "/config_edit-"+get_data('logs')+".log", "a")
else:
mess = get_data('date_in_log') + action + "\n" mess = get_data('date_in_log') + action + "\n"
log = open(log_path + "/checker-"+get_data('logs')+".log", "a") log = open(log_path + "/checker-"+get_data('logs')+".log", "a")
elif kwargs.get('metrics') == 1:
mess = get_data('date_in_log') + action + "\n"
log = open(log_path + "/metrics-"+get_data('logs')+".log", "a")
else:
mess = get_data('date_in_log') + " from " + IP + " user: " + login + " " + action + " for: " + serv + "\n"
log = open(log_path + "/config_edit-"+get_data('logs')+".log", "a")
try: try:
log.write(mess) log.write(mess)
@ -272,13 +275,12 @@ def show_config(cfg):
def diff_config(oldcfg, cfg): def diff_config(oldcfg, cfg):
import subprocess import subprocess
cmd="/bin/diff -ub %s %s" % (oldcfg, cfg)
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, universal_newlines=True)
stdout, stderr = p.communicate()
output = stdout.splitlines()
log_path = get_config_var('main', 'log_path') log_path = get_config_var('main', 'log_path')
diff = "" diff = ""
date = get_data('date_in_log') date = get_data('date_in_log')
cmd="/bin/diff -ub %s %s" % (oldcfg, cfg)
output, stderr = subprocess_execute(cmd)
for line in output: for line in output:
diff += date + " " + line + "\n" diff += date + " " + line + "\n"

29
app/metrics.py Normal file
View File

@ -0,0 +1,29 @@
#!/usr/bin/env python3
import os
import sql
import http
import funct
import sql
from jinja2 import Environment, FileSystemLoader
env = Environment(loader=FileSystemLoader('templates/'))
template = env.get_template('metrics.html')
print('Content-type: text/html\n')
funct.check_login()
try:
cookie = http.cookies.SimpleCookie(os.environ.get("HTTP_COOKIE"))
user_id = cookie.get('uuid')
user = sql.get_user_name_by_uuid(user_id.value)
servers = sql.get_dick_permit()
token = sql.get_token(user_id.value)
except:
pass
template = template.render(h2 = 1, title = "Metrics",
autorefresh = 1,
role = sql.get_user_role_by_uuid(user_id.value),
user = user,
onclick = "metricsShow()",
token = token)
print(template)

View File

@ -352,4 +352,85 @@ if form.getvalue('masteradd'):
os.system("rm -f %s" % script) os.system("rm -f %s" % script)
if form.getvalue('haproxyaddserv'): if form.getvalue('haproxyaddserv'):
funct.install_haproxy(form.getvalue('haproxyaddserv'), syn_flood=form.getvalue('syn_flood')) funct.install_haproxy(form.getvalue('haproxyaddserv'), syn_flood=form.getvalue('syn_flood'))
if form.getvalue('metrics'):
from datetime import timedelta
from bokeh.plotting import figure, output_file, show
from bokeh.models import ColumnDataSource, HoverTool, DatetimeTickFormatter, DatePicker
from bokeh.layouts import widgetbox, gridplot
from bokeh.models.widgets import Button, RadioButtonGroup, Select
import pandas as pd
import json
servers = sql.select_servers_metrics()
p = {}
for serv in servers:
serv = serv[0]
p[serv] = {}
metric = sql.select_metrics(serv)
metrics = {}
for i in metric:
rep_date = str(i[5])
metrics[rep_date] = {}
metrics[rep_date]['server'] = str(i[0])
metrics[rep_date]['curr_con'] = str(i[1])
metrics[rep_date]['curr_ssl_con'] = str(i[2])
metrics[rep_date]['sess_rate'] = str(i[3])
metrics[rep_date]['max_sess_rate'] = str(i[4])
df = pd.DataFrame.from_dict(metrics, orient="index")
df = df.fillna(0)
df.index = pd.to_datetime(df.index)
df.index.name = 'Date'
df.sort_index(inplace=True)
source = ColumnDataSource(df)
output_file("templates/metrics_out.html")
x_min = df.index.min() - pd.Timedelta(hours=1)
x_max = df.index.max() + pd.Timedelta(minutes=1)
p[serv] = figure(
tools="pan,box_zoom,reset,wheel_zoom",
title=metric[0][0],
x_axis_type="datetime", y_axis_label='Connections',
x_range = (x_max.timestamp()*1000-60*100000, x_max.timestamp()*1000)
)
hover = HoverTool(
tooltips=[
("Connections", "@curr_con"),
("SSL connections", "@curr_ssl_con"),
("Sessions rate", "@sess_rate"),
("Max sessions rate", "@max_sess_rate"),
],
mode='mouse'
)
p[serv].ygrid.band_fill_color = "olive"
p[serv].ygrid.band_fill_alpha = 0.1
p[serv].y_range.start = 0
p[serv].y_range.end = int(df['max_sess_rate'].max()) + 100
p[serv].add_tools(hover)
p[serv].line("Date", "curr_con", source=source, alpha=0.5, color='#5cb85c', line_width=2, legend="Conn")
p[serv].line("Date", "curr_ssl_con", source=source, alpha=0.5, color="#5d9ceb", line_width=2, legend="SSL con")
p[serv].line("Date", "sess_rate", source=source, alpha=0.5, color="#33414e", line_width=2, legend="Sessions")
p[serv].line("Date", "max_sess_rate", source=source, alpha=0.5, color="red", line_width=2, legend="Max sess")
p[serv].legend.orientation = "horizontal"
#select = Select(title="Option:", value="foo", options=["foo", "bar", "baz", "quux"])
#show(widgetbox(select, width=300))
plots = []
i = 0
for key, value in p.items():
plots.append(value)
#plots = plots.sort()
grid = gridplot(plots, ncols=2, plot_width=800, plot_height=250, toolbar_location = "left", toolbar_options=dict(logo=None))
show(grid)

View File

@ -3,19 +3,14 @@ import os
import cgi import cgi
import sql import sql
cgi_path = funct.get_config_var('main', 'cgi_path')
fullpath = funct.get_config_var('main', 'fullpath')
stats_port= funct.get_config_var('haproxy', 'stats_port')
haproxy_config_path = funct.get_config_var('haproxy', 'haproxy_config_path')
status_command = funct.get_config_var('haproxy', 'status_command')
hap_configs_dir = funct.get_config_var('configs', 'haproxy_save_configs_dir')
form = cgi.FieldStorage() form = cgi.FieldStorage()
def get_overview(): def get_overview():
import os, http.cookies import http.cookies
from jinja2 import Environment, FileSystemLoader from jinja2 import Environment, FileSystemLoader
env = Environment(loader=FileSystemLoader('templates/ajax')) env = Environment(loader=FileSystemLoader('templates/ajax'))
template = env.get_template('overview.html') template = env.get_template('overview.html')
haproxy_config_path = funct.get_config_var('haproxy', 'haproxy_config_path')
cookie = http.cookies.SimpleCookie(os.environ.get("HTTP_COOKIE")) cookie = http.cookies.SimpleCookie(os.environ.get("HTTP_COOKIE"))
user_id = cookie.get('uuid') user_id = cookie.get('uuid')
@ -31,9 +26,9 @@ def get_overview():
template = template.render(service_status = servers, role = sql.get_user_role_by_uuid(user_id.value)) template = template.render(service_status = servers, role = sql.get_user_role_by_uuid(user_id.value))
print(template) print(template)
def get_overviewServers(): def get_overviewServers():
import os, http.cookies import http.cookies
from jinja2 import Environment, FileSystemLoader from jinja2 import Environment, FileSystemLoader
env = Environment(loader=FileSystemLoader('templates/ajax')) env = Environment(loader=FileSystemLoader('templates/ajax'))
template = env.get_template('overviewServers.html') template = env.get_template('overviewServers.html')
@ -60,7 +55,6 @@ def get_overviewServers():
server_status = (server[1],server[2], out1, funct.ssh_command(server[2], commands),funct.show_backends(server[2], ret=1)) server_status = (server[1],server[2], out1, funct.ssh_command(server[2], commands),funct.show_backends(server[2], ret=1))
servers.append(server_status) servers.append(server_status)
#print(servers)
template = template.render(service_status = servers, role = sql.get_user_role_by_uuid(user_id.value)) template = template.render(service_status = servers, role = sql.get_user_role_by_uuid(user_id.value))
print(template) print(template)
@ -72,6 +66,11 @@ def get_map(serv):
matplotlib.use('Agg') matplotlib.use('Agg')
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
cgi_path = funct.get_config_var('main', 'cgi_path')
fullpath = funct.get_config_var('main', 'fullpath')
stats_port= funct.get_config_var('haproxy', 'stats_port')
haproxy_config_path = funct.get_config_var('haproxy', 'haproxy_config_path')
hap_configs_dir = funct.get_config_var('configs', 'haproxy_save_configs_dir')
date = funct.get_data('config') date = funct.get_data('config')
cfg = hap_configs_dir + serv + "-" + date + ".cfg" cfg = hap_configs_dir + serv + "-" + date + ".cfg"
@ -186,6 +185,7 @@ def comapre_show():
import subprocess import subprocess
left = form.getvalue('left') left = form.getvalue('left')
right = form.getvalue('right') right = form.getvalue('right')
hap_configs_dir = funct.get_config_var('configs', 'haproxy_save_configs_dir')
cmd='diff -ub %s%s %s%s' % (hap_configs_dir, left, hap_configs_dir, right) cmd='diff -ub %s%s %s%s' % (hap_configs_dir, left, hap_configs_dir, right)
output, stderr = funct.subprocess_execute(cmd) output, stderr = funct.subprocess_execute(cmd)

View File

@ -110,13 +110,13 @@ def update_group(name, descript, id):
cur.close() cur.close()
con.close() con.close()
def add_server(hostname, ip, group, typeip, enable, master, cred, alert): def add_server(hostname, ip, group, typeip, enable, master, cred, alert, metrics):
con, cur = create_db.get_cur() con, cur = create_db.get_cur()
sql = """ sql = """
INSERT INTO servers INSERT INTO servers
(hostname, ip, groups, type_ip, enable, master, cred, alert) (hostname, ip, groups, type_ip, enable, master, cred, alert, metrics)
VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s') VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s')
""" % (hostname, ip, group, typeip, enable, master, cred, alert) """ % (hostname, ip, group, typeip, enable, master, cred, alert, metrics)
try: try:
cur.execute(sql) cur.execute(sql)
con.commit() con.commit()
@ -143,7 +143,7 @@ def delete_server(id):
cur.close() cur.close()
con.close() con.close()
def update_server(hostname, ip, group, typeip, enable, master, id, cred, alert): def update_server(hostname, ip, group, typeip, enable, master, id, cred, alert, metrics):
con, cur = create_db.get_cur() con, cur = create_db.get_cur()
sql = """update servers set sql = """update servers set
hostname = '%s', hostname = '%s',
@ -153,8 +153,9 @@ def update_server(hostname, ip, group, typeip, enable, master, id, cred, alert):
enable = '%s', enable = '%s',
master = '%s', master = '%s',
cred = '%s', cred = '%s',
alert = '%s' alert = '%s',
where id = '%s'""" % (hostname, ip, group, typeip, enable, master, cred, alert, id) metrics = '%s'
where id = '%s'""" % (hostname, ip, group, typeip, enable, master, cred, alert, metrics, id)
try: try:
cur.execute(sql) cur.execute(sql)
con.commit() con.commit()
@ -636,6 +637,60 @@ def update_telegram(token, chanel, group, id):
cur.close() cur.close()
con.close() con.close()
def insert_mentrics(serv, curr_con, cur_ssl_con, sess_rate, max_sess_rate):
con, cur = create_db.get_cur()
if mysql_enable == '1':
sql = """ insert into metrics (serv, curr_con, cur_ssl_con, sess_rate, max_sess_rate, date) values('%s', '%s', '%s', '%s', '%s', now()) """ % (serv, curr_con, cur_ssl_con, sess_rate, max_sess_rate)
else:
sql = """ insert into metrics (serv, curr_con, cur_ssl_con, sess_rate, max_sess_rate, date) values('%s', '%s', '%s', '%s', '%s', datetime('now', 'localtime')) """ % (serv, curr_con, cur_ssl_con, sess_rate, max_sess_rate)
try:
cur.execute(sql)
con.commit()
except sqltool.Error as e:
print('<span class="alert alert-danger" id="error">An error occurred: ' + e.args[0] + ' <a title="Close" id="errorMess"><b>X</b></a></span>')
con.rollback()
cur.close()
con.close()
def delete_mentrics():
con, cur = create_db.get_cur()
if mysql_enable == '1':
sql = """ delete from metrics where date < now() - INTERVAL 3 day """
else:
sql = """ delete from metrics where date < datetime('now', '-3 days') """
try:
cur.execute(sql)
con.commit()
except sqltool.Error as e:
print('<span class="alert alert-danger" id="error">An error occurred: ' + e.args[0] + ' <a title="Close" id="errorMess"><b>X</b></a></span>')
con.rollback()
cur.close()
con.close()
def select_metrics(serv, **kwargs):
con, cur = create_db.get_cur()
sql = """ select * from metrics where serv = '%s' order by `date` desc """ % serv
try:
cur.execute(sql)
except sqltool.Error as e:
print('<span class="alert alert-danger" id="error">An error occurred: ' + e + ' <a title="Close" id="errorMess"><b>X</b></a></span>')
else:
return cur.fetchall()
cur.close()
con.close()
def select_servers_metrics(**kwargs):
con, cur = create_db.get_cur()
sql = """ select ip from servers where metrics = '1' """
try:
cur.execute(sql)
except sqltool.Error as e:
print('<span class="alert alert-danger" id="error">An error occurred: ' + e + ' <a title="Close" id="errorMess"><b>X</b></a></span>')
else:
return cur.fetchall()
cur.close()
con.close()
def show_update_telegram(token, page): def show_update_telegram(token, page):
from jinja2 import Environment, FileSystemLoader from jinja2 import Environment, FileSystemLoader
env = Environment(loader=FileSystemLoader('templates/ajax')) env = Environment(loader=FileSystemLoader('templates/ajax'))
@ -769,6 +824,7 @@ if form.getvalue('newserver') is not None:
master = form.getvalue('slave') master = form.getvalue('slave')
cred = form.getvalue('cred') cred = form.getvalue('cred')
alert = form.getvalue('alert_en') alert = form.getvalue('alert_en')
metrics = form.getvalue('metrics')
page = form.getvalue('page') page = form.getvalue('page')
page = page.split("#")[0] page = page.split("#")[0]
if ip is None or group is None or cred is None: if ip is None or group is None or cred is None:
@ -776,7 +832,7 @@ if form.getvalue('newserver') is not None:
print(error_mess) print(error_mess)
else: else:
print('Content-type: text/html\n') print('Content-type: text/html\n')
if add_server(hostname, ip, group, typeip, enable, master, cred, alert): if add_server(hostname, ip, group, typeip, enable, master, cred, alert, metrics):
show_update_server(ip, page) show_update_server(ip, page)
if form.getvalue('serverdel') is not None: if form.getvalue('serverdel') is not None:
@ -818,13 +874,14 @@ if form.getvalue('updateserver') is not None:
id = form.getvalue('id') id = form.getvalue('id')
cred = form.getvalue('cred') cred = form.getvalue('cred')
alert = form.getvalue('alert_en') alert = form.getvalue('alert_en')
metrics = form.getvalue('metrics')
if name is None or ip is None: if name is None or ip is None:
print('Content-type: text/html\n') print('Content-type: text/html\n')
print(error_mess) print(error_mess)
else: else:
print('Content-type: text/html\n') print('Content-type: text/html\n')
#if funct.ssh_connect(ip, check=1): #if funct.ssh_connect(ip, check=1):
update_server(name, ip, group, typeip, enable, master, id, cred, alert) update_server(name, ip, group, typeip, enable, master, id, cred, alert, metrics)
#else: #else:
# print('<span class="alert alert-danger" id="error"><a title="Close" id="errorMess"><b>X</b></a></span>') # print('<span class="alert alert-danger" id="error"><a title="Close" id="errorMess"><b>X</b></a></span>')

View File

@ -165,6 +165,7 @@
<td>Enable</td> <td>Enable</td>
<td><span title="Vitrual IP, something like VRRP">Virt(?)</span></td> <td><span title="Vitrual IP, something like VRRP">Virt(?)</span></td>
<td><span title="Alert if backend change status. Before enable add Telgram chanel at Checker tab">Alert(?)</span></td> <td><span title="Alert if backend change status. Before enable add Telgram chanel at Checker tab">Alert(?)</span></td>
<td><span title="Enable save and show metrics">Metrics(?)</span></td>
<td><span title="Actions with master config will automatically apply on slave">Slave for (?)</span></td> <td><span title="Actions with master config will automatically apply on slave">Slave for (?)</span></td>
<td>Credentials</td> <td>Credentials</td>
<td></td> <td></td>
@ -211,6 +212,13 @@
<label for="alert-{{server.0}}"></label><input type="checkbox" id="alert-{{server.0}}"> <label for="alert-{{server.0}}"></label><input type="checkbox" id="alert-{{server.0}}">
{% endif %} {% endif %}
</td> </td>
<td>
{% if server.9 == 1 %}
<label for="metrics-{{server.0}}"></label><input type="checkbox" id="metrics-{{server.0}}" checked>
{% else %}
<label for="metrics-{{server.0}}"></label><input type="checkbox" id="metrics-{{server.0}}">
{% endif %}
</td>
<td> <td>
<select id="slavefor-{{server.0}}"> <select id="slavefor-{{server.0}}">
<option value="0" selected>Not slave</option> <option value="0" selected>Not slave</option>
@ -251,6 +259,7 @@
<td>Enable</td> <td>Enable</td>
<td><span title="Vitrual IP, something like VRRP">Virt(?)</span></td> <td><span title="Vitrual IP, something like VRRP">Virt(?)</span></td>
<td><span title="Alert if backend change status">Alert(?)</span></td> <td><span title="Alert if backend change status">Alert(?)</span></td>
<td><span title="Enable save and show metrics">Metrics(?)</span></td>
<td title="Actions with master config will automatically apply on slave">Slave for</td> <td title="Actions with master config will automatically apply on slave">Slave for</td>
<td>Credentials</td> <td>Credentials</td>
<td></td> <td></td>
@ -279,6 +288,9 @@
<td> <td>
<label for="alert"></label><input type="checkbox" id="alert"> <label for="alert"></label><input type="checkbox" id="alert">
</td> </td>
<td>
<label for="metrics"></label><input type="checkbox" id="metrics">
</td>
<td> <td>
<select id="slavefor"> <select id="slavefor">
<option value="0" selected>Not slave</option> <option value="0" selected>Not slave</option>

View File

@ -43,6 +43,13 @@
<label for="alert-{{server.0}}"></label><input type="checkbox" id="alert-{{server.0}}"> <label for="alert-{{server.0}}"></label><input type="checkbox" id="alert-{{server.0}}">
{% endif %} {% endif %}
</td> </td>
<td>
{% if server.9 == 1 %}
<label for="metrics-{{server.0}}"></label><input type="checkbox" id="metrics-{{server.0}}" checked>
{% else %}
<label for="metrics-{{server.0}}"></label><input type="checkbox" id="metrics-{{server.0}}">
{% endif %}
</td>
<td> <td>
<select id="slavefor-{{server.0}}"> <select id="slavefor-{{server.0}}">
<option value="0" selected>Not slave</option> <option value="0" selected>Not slave</option>

View File

@ -49,6 +49,7 @@
<li><a href=/app/logs.py title="View logs" class="logs head-submenu"> Logs</a></li> <li><a href=/app/logs.py title="View logs" class="logs head-submenu"> Logs</a></li>
<li><a href=/app/map.py title="View map" class="map head-submenu">Map</a></li> <li><a href=/app/map.py title="View map" class="map head-submenu">Map</a></li>
<li><a href=/app/edit.py title="Runtime API" class="runtime head-submenu">Runtime API</a></li> <li><a href=/app/edit.py title="Runtime API" class="runtime head-submenu">Runtime API</a></li>
<li><a href=/app/metrics.py title="Metrics" class="overview-link head-submenu">Metrics</a></li>
</li> </li>
<li><a title="Actions with Haproxy configs" class="config-show">Haproxy</a> <li><a title="Actions with Haproxy configs" class="config-show">Haproxy</a>
<li><a href=/app/configshow.py title="Show Haproxy Config" class="config-show head-submenu">Show config</a></li> <li><a href=/app/configshow.py title="Show Haproxy Config" class="config-show head-submenu">Show config</a></li>
@ -96,7 +97,7 @@
</ul> </ul>
</nav> </nav>
<div class="copyright-menu"> <div class="copyright-menu">
HAproxy-WI v2.7.3 HAproxy-WI v2.8
<br> <br>
<a href="https://www.patreon.com/haproxy_wi" title="Donate" target="_blank" style="color: #fff; margin-left: 30px; color: red;" class="patreon"> Patreon</a> <a href="https://www.patreon.com/haproxy_wi" title="Donate" target="_blank" style="color: #fff; margin-left: 30px; color: red;" class="patreon"> Patreon</a>
</div> </div>

View File

@ -0,0 +1,29 @@
{% extends "base.html" %}
{% block content %}
<style>
iframe {
border: none;
}
</style>
<div id="metrics_iframe"></div>
<script>
function callIframe(url, callback) {
$('#metrics_iframe').html('<iframe id="metrics" style="width:100%;height:100%;" />');
$('iframe#metrics').attr('src', url);
$('iframe#metrics').load(function() {
callback(this);
});
}
function loadMetrics() {
callIframe('templates/metrics_out.html', function(){
$.get( "options.py?metrics=1&token="+$('#token').val(), function( data ) {
$( ".result" ).html( data );
});
});
}
loadMetrics()
</script>
{% endblock %}

View File

@ -24,6 +24,7 @@
<td>Enable</td> <td>Enable</td>
<td><span title="Vitrual IP, something like VRRP">Virt(?)</span></td> <td><span title="Vitrual IP, something like VRRP">Virt(?)</span></td>
<td><span title="Alert if backend change status. Before enable add Telgram chanel at Checker tab">Alert(?)</span></td> <td><span title="Alert if backend change status. Before enable add Telgram chanel at Checker tab">Alert(?)</span></td>
<td><span title="Enable save and show metrics">Metrics(?)</span></td>
<td><span title="Actions with master config will automatically apply on slave">Slave for (?)</span></td> <td><span title="Actions with master config will automatically apply on slave">Slave for (?)</span></td>
<td>Credentials</td> <td>Credentials</td>
<td></td> <td></td>
@ -61,6 +62,13 @@
<label for="alert-{{server.0}}"></label><input type="checkbox" id="alert-{{server.0}}"> <label for="alert-{{server.0}}"></label><input type="checkbox" id="alert-{{server.0}}">
{% endif %} {% endif %}
</td> </td>
<td>
{% if server.9 == 1 %}
<label for="metrics-{{server.0}}"></label><input type="checkbox" id="metrics-{{server.0}}" checked>
{% else %}
<label for="metrics-{{server.0}}"></label><input type="checkbox" id="metrics-{{server.0}}">
{% endif %}
</td>
<td> <td>
<select id="slavefor-{{server.0}}"> <select id="slavefor-{{server.0}}">
<option selected value="0">Not slave</option> <option selected value="0">Not slave</option>
@ -102,6 +110,7 @@
<td>Enable</td> <td>Enable</td>
<td><span title="Vitrual IP, something like VRRP">Virt(?)</span></td> <td><span title="Vitrual IP, something like VRRP">Virt(?)</span></td>
<td><span title="Alert if backend change status">Alert(?)</span></td> <td><span title="Alert if backend change status">Alert(?)</span></td>
<td><span title="Enable save and show metrics">Metrics(?)</span></td>
<td title="Actions with master config will automatically apply on slave">Slave for</td> <td title="Actions with master config will automatically apply on slave">Slave for</td>
<td>Credentials</td> <td>Credentials</td>
<td></td> <td></td>
@ -123,6 +132,9 @@
<td> <td>
<label for="alert"></label><input type="checkbox" id="alert"> <label for="alert"></label><input type="checkbox" id="alert">
</td> </td>
<td>
<label for="metrics"></label><input type="checkbox" id="metrics">
</td>
<td> <td>
<select id="slavefor"> <select id="slavefor">
<option selected value="0">Not slave</option> <option selected value="0">Not slave</option>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 327 KiB

After

Width:  |  Height:  |  Size: 335 KiB

View File

@ -17,7 +17,7 @@ jQuery.expr[':'].regex = function(elem, index, match) {
} }
window.onblur= function() { window.onblur= function() {
window.onfocus= function () { window.onfocus= function () {
if($('.auto-refresh-pause').attr('style') == "display: inline; margin-top: 4px; margin-left: -25px;" && Cookies.get('auto-refresh') > 5000) { if(Cookies.get('auto-refresh-pause') == "0" && Cookies.get('auto-refresh') > 5000) {
if (cur_url[0] == "logs.py") { if (cur_url[0] == "logs.py") {
showLog(); showLog();
} else if (cur_url[0] == "viewsttats.py") { } else if (cur_url[0] == "viewsttats.py") {
@ -74,6 +74,7 @@ function setRefreshInterval(interval) {
} else { } else {
clearInterval(intervalId); clearInterval(intervalId);
Cookies.set('auto-refresh', interval, { expires: 365 }); Cookies.set('auto-refresh', interval, { expires: 365 });
Cookies.set('auto-refresh-pause', "0", { expires: 365 });
startSetInterval(interval); startSetInterval(interval);
hideAutoRefreshDiv(); hideAutoRefreshDiv();
autoRefreshStyle(interval); autoRefreshStyle(interval);
@ -81,33 +82,42 @@ function setRefreshInterval(interval) {
} }
function startSetInterval(interval) { function startSetInterval(interval) {
if (cur_url[0] == "logs.py") { if(Cookies.get('auto-refresh-pause') == "0") {
intervalId = setInterval('showLog()', interval); if (cur_url[0] == "logs.py") {
showLog(); intervalId = setInterval('showLog()', interval);
} else if (cur_url[0] == "viewsttats.py") { showLog();
intervalId = setInterval('showStats()', interval); } else if (cur_url[0] == "viewsttats.py") {
showStats() intervalId = setInterval('showStats()', interval);
} else if (cur_url[0] == "overview.py") { showStats()
if(interval < 60000) { } else if (cur_url[0] == "overview.py") {
interval = 60000; if(interval < 60000) {
} interval = 60000;
intervalId = setInterval('showOverview()', interval); }
showOverview(); intervalId = setInterval('showOverview()', interval);
} else if (cur_url[0] == "viewlogs.py") { showOverview();
intervalId = setInterval('viewLogs()', interval); } else if (cur_url[0] == "viewlogs.py") {
viewLogs(); intervalId = setInterval('viewLogs()', interval);
} viewLogs();
} else if (cur_url[0] == "metrics.py") {
intervalId = setInterval('loadMetrics()', interval);
loadMetrics();
}
} else {
pauseAutoRefresh();
}
} }
function pauseAutoRefresh() { function pauseAutoRefresh() {
clearInterval(intervalId); clearInterval(intervalId);
$(function() { $(function() {
$('.auto-refresh-pause').css('display', 'none'); $('.auto-refresh-pause').css('display', 'none');
$('.auto-refresh-resume').css('display', 'inline'); $('.auto-refresh-resume').css('display', 'inline');
Cookies.set('auto-refresh-pause', "1", { expires: 365 });
}); });
} }
function pauseAutoResume(){ function pauseAutoResume(){
var autoRefresh = Cookies.get('auto-refresh'); var autoRefresh = Cookies.get('auto-refresh');
setRefreshInterval(autoRefresh); setRefreshInterval(autoRefresh);
Cookies.set('auto-refresh-pause', "0", { expires: 365 });
} }
function hideAutoRefreshDiv() { function hideAutoRefreshDiv() {

View File

@ -31,6 +31,8 @@ $( function() {
$("#ajax").html('<div class="alert alert-danger">Please fill in all fields</div>') $("#ajax").html('<div class="alert alert-danger">Please fill in all fields</div>')
} else if(! $("#vrrp-ip").val().match(ipformat)) { } else if(! $("#vrrp-ip").val().match(ipformat)) {
$("#ajax").html('<div class="alert alert-danger">Please enter IP in "VRRP IP" field</div>') $("#ajax").html('<div class="alert alert-danger">Please enter IP in "VRRP IP" field</div>')
} else if ($("#master").val() == $("#slave").val() ){
$("#ajax").html('<div class="alert alert-danger">Master and slave must be diff servers</div>')
} else { } else {
$("#ajax").html('<div class="alert alert-warning">Please don\'t close and don\'t represh page. Wait until the work is completed. This may take some time </div>'); $("#ajax").html('<div class="alert alert-warning">Please don\'t close and don\'t represh page. Wait until the work is completed. This may take some time </div>');
$.ajax( { $.ajax( {
@ -101,6 +103,7 @@ $( function() {
if ($('#syn_flood').is(':checked')) { if ($('#syn_flood').is(':checked')) {
syn_flood = '1'; syn_flood = '1';
} }
$("#ajax").html('<div class="alert alert-warning">Please don\'t close and don\'t represh page. Wait until the work is completed. This may take some time </div>');
$.ajax( { $.ajax( {
url: "options.py", url: "options.py",
data: { data: {
@ -181,6 +184,7 @@ $( function() {
var typeip = 0; var typeip = 0;
var enable = 0; var enable = 0;
var alert_en = 0; var alert_en = 0;
var metrics = 0;
if ($('#typeip').is(':checked')) { if ($('#typeip').is(':checked')) {
typeip = '1'; typeip = '1';
} }
@ -190,6 +194,9 @@ $( function() {
if ($('#alert').is(':checked')) { if ($('#alert').is(':checked')) {
var alert_en = 0; var alert_en = 0;
} }
if ($('#metrics').is(':checked')) {
var alert_en = 0;
}
$.ajax( { $.ajax( {
url: "sql.py", url: "sql.py",
data: { data: {
@ -201,6 +208,7 @@ $( function() {
slave: $('#slavefor' ).val(), slave: $('#slavefor' ).val(),
cred: $('#credentials').val(), cred: $('#credentials').val(),
alert_en: alert_en, alert_en: alert_en,
metrics: metrics,
page: cur_url[0] page: cur_url[0]
}, },
type: "GET", type: "GET",
@ -621,6 +629,7 @@ function updateServer(id) {
var typeip = 0; var typeip = 0;
var enable = 0; var enable = 0;
var alert_en = 0; var alert_en = 0;
var metrics = 0;
if ($('#typeip-'+id).is(':checked')) { if ($('#typeip-'+id).is(':checked')) {
typeip = '1'; typeip = '1';
} }
@ -630,6 +639,9 @@ function updateServer(id) {
if ($('#alert-'+id).is(':checked')) { if ($('#alert-'+id).is(':checked')) {
alert_en = '1'; alert_en = '1';
} }
if ($('#metrics-'+id).is(':checked')) {
metrics = '1';
}
var servergroup = $('#servergroup-'+id+' option:selected' ).val(); var servergroup = $('#servergroup-'+id+' option:selected' ).val();
if (cur_url[0] == "servers.py") { if (cur_url[0] == "servers.py") {
servergroup = $('#servergroup-'+id).val(); servergroup = $('#servergroup-'+id).val();
@ -645,6 +657,7 @@ function updateServer(id) {
slave: $('#slavefor-'+id+' option:selected' ).val(), slave: $('#slavefor-'+id+' option:selected' ).val(),
cred: $('#credentials-'+id+' option:selected').val(), cred: $('#credentials-'+id+' option:selected').val(),
id: id, id: id,
metrics: metrics,
alert_en: alert_en alert_en: alert_en
}, },
type: "GET", type: "GET",

View File

@ -40,7 +40,7 @@ echo ""
echo "################################" echo "################################"
if hash apt-get 2>/dev/null; then if hash apt-get 2>/dev/null; then
apt-get install git net-tools lshw dos2unix apache2 gcc netcat python3-pip -y apt-get install git net-tools lshw dos2unix apache2 gcc netcat python3-pip gcc-c++ -y
HTTPD_CONFIG="/etc/apache2/apache2.conf" HTTPD_CONFIG="/etc/apache2/apache2.conf"
HAPROXY_WI_VHOST_CONF="/etc/apache2/sites-enabled/haproxy-wi.conf" HAPROXY_WI_VHOST_CONF="/etc/apache2/sites-enabled/haproxy-wi.conf"
HTTPD_NAME="apache2" HTTPD_NAME="apache2"
@ -57,7 +57,7 @@ else
yum -y install epel-release yum -y install epel-release
fi fi
yum -y install git nmap-ncat net-tools lshw python34 dos2unix python34-pip httpd mod_ssl python34-devel yum -y install git nmap-ncat net-tools python34 dos2unix python34-pip httpd python34-devel gcc-c++
HTTPD_CONFIG="/etc/httpd/conf/httpd.conf" HTTPD_CONFIG="/etc/httpd/conf/httpd.conf"
HAPROXY_WI_VHOST_CONF="/etc/httpd/conf.d/haproxy-wi.conf" HAPROXY_WI_VHOST_CONF="/etc/httpd/conf.d/haproxy-wi.conf"
HTTPD_NAME="httpd" HTTPD_NAME="httpd"
@ -190,13 +190,54 @@ cat << EOF > /etc/logrotate.d/checker
} }
EOF EOF
cat << EOF > /etc/systemd/system/multi-user.target.wants/metrics_haproxy.service
[Unit]
Description=Haproxy metrics
After=syslog.target network.target
[Service]
Type=simple
WorkingDirectory=/var/www/haproxy-wi/app/
ExecStart=/var/www/haproxy-wi/app/tools/metrics_master.py
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=metrics
RestartSec=2s
Restart=on-failure
TimeoutStopSec=1s
[Install]
WantedBy=multi-user.target
EOF
cat << EOF > /etc/rsyslog.d/metrics.conf
if $programname startswith 'metrics' then /var/www/$HOME_HAPROXY_WI/log/metrics-error.log
& stop
EOF
cat << EOF > /etc/logrotate.d/metrics
/var/www/$HOME_HAPROXY_WI/log/metrics-error.log {
daily
rotate 10
missingok
notifempty
create 0644 apache apache
dateext
sharedscripts
}
EOF
sed -i 's/#$UDPServerRun 514/$UDPServerRun 514/g' /etc/rsyslog.conf sed -i 's/#$UDPServerRun 514/$UDPServerRun 514/g' /etc/rsyslog.conf
sed -i 's/#$ModLoad imudp/$ModLoad imudp/g' /etc/rsyslog.conf sed -i 's/#$ModLoad imudp/$ModLoad imudp/g' /etc/rsyslog.conf
systemctl daemon-reload systemctl daemon-reload
systemctl restart logrotate systemctl restart logrotate
systemctl restart rsyslog systemctl restart rsyslog
systemctl restart cmetrics_haproxy.service
systemctl restart checker_haproxy.service systemctl restart checker_haproxy.service
systemctl enable metrics_haproxy.service
systemctl enable checker_haproxy.service systemctl enable checker_haproxy.service
if hash apt-get 2>/dev/null; then if hash apt-get 2>/dev/null; then

View File

@ -11,4 +11,6 @@ matplotlib==2.1.2
urllib3==1.22 urllib3==1.22
future==0.13.1 future==0.13.1
mysql-connector-python==8.0.11 mysql-connector-python==8.0.11
Jinja2==2.10 Jinja2==2.10
pandas==0.22.0
bokeh==0.13.0

View File

@ -10,7 +10,11 @@ mkdir app/certs
chmod +x app/*py chmod +x app/*py
chmod +x app/tools/*py chmod +x app/tools/*py
if hash apt-get 2>/dev/null; then
apt-get install git net-tools lshw dos2unix apache2 gcc netcat python3-pip gcc-c++ -y
else
yum -y install git nmap-ncat net-tools python34 dos2unix python34-pip httpd python34-devel gcc-c++
fi
at << EOF > /etc/systemd/system/multi-user.target.wants/checker_haproxy.service at << EOF > /etc/systemd/system/multi-user.target.wants/checker_haproxy.service
[Unit] [Unit]
@ -51,13 +55,54 @@ $(pwd)/log/checker-error.log {
} }
EOF EOF
cat << EOF > /etc/systemd/system/multi-user.target.wants/metrics_haproxy.service
[Unit]
Description=Haproxy metrics
After=syslog.target network.target
[Service]
Type=simple
WorkingDirectory=/var/www/haproxy-wi/app/
ExecStart=/var/www/haproxy-wi/app/tools/metrics_master.py
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=metrics
RestartSec=2s
Restart=on-failure
TimeoutStopSec=1s
[Install]
WantedBy=multi-user.target
EOF
cat << EOF > /etc/rsyslog.d/metrics.conf
if $programname startswith 'metrics' then /var/www/$HOME_HAPROXY_WI/log/metrics-error.log
& stop
EOF
cat << EOF > /etc/logrotate.d/metrics
/var/www/$HOME_HAPROXY_WI/log/metrics-error.log {
daily
rotate 10
missingok
notifempty
create 0644 apache apache
dateext
sharedscripts
}
EOF
sed -i 's/#$UDPServerRun 514/$UDPServerRun 514/g' /etc/rsyslog.conf sed -i 's/#$UDPServerRun 514/$UDPServerRun 514/g' /etc/rsyslog.conf
sed -i 's/#$ModLoad imudp/$ModLoad imudp/g' /etc/rsyslog.conf sed -i 's/#$ModLoad imudp/$ModLoad imudp/g' /etc/rsyslog.conf
systemctl daemon-reload systemctl daemon-reload
systemctl restart logrotate systemctl restart logrotate
systemctl restart rsyslog systemctl restart rsyslog
systemctl restart cmetrics_haproxy.service
systemctl restart checker_haproxy.service systemctl restart checker_haproxy.service
systemctl enable metrics_haproxy.service
systemctl enable checker_haproxy.service systemctl enable checker_haproxy.service
chown -R apache:apache * chown -R apache:apache *