Appeared ability edit not whole config. just separate sections
Some new design
Improved Options
Bugs fixed
pull/145/head
Pavel Loginov 2019-09-20 09:42:19 +03:00
parent af6e7c97c0
commit 8ad92c1342
26 changed files with 589 additions and 170 deletions

View File

@ -3,7 +3,7 @@ Web interface(user-friendly web GUI, alerting, monitoring and secure) for managi
# Donate
Support the project
[![Donate](https://img.shields.io/badge/PayPal-Donate-brightgreen.svg)](https://www.paypal.me/haproxywi) or [Patreon](https://www.patreon.com/haproxy_wi/overview)
[![Donate](https://img.shields.io/badge/PayPal-Donate-brightgreen.svg)](https://www.paypal.me/loginovpavel) or [Patreon](https://www.patreon.com/haproxy_wi/overview)
# Youtube
[Demo video](https://www.youtube.com/channel/UCo0lCg24j-H4f0S9kMjp-_w)
@ -47,8 +47,14 @@ Support the project
# Install
## RPM
Install repository^
```
yum install https://repo.haproxy-wi.org/el7/haproxy-wi-release-7-1-0.noarch.rpm
```
After install HAProxy-WI:
```
yum install haproxy-wi
```
## Script
The installer will ask you a few questions
```

View File

@ -234,6 +234,66 @@ def diff_config(oldcfg, cfg):
print('<center><div class="alert alert-danger">Can\'t read write change to log. %s</div></center>' % stderr)
pass
def get_sections(config):
record = False
return_config = list()
with open(config, 'r') as f:
for line in f:
if line.startswith('listen') or line.startswith('frontend') or line.startswith('backend') or line.startswith('cache') or line.startswith('defaults') or line.startswith('global'):
line = line.strip()
return_config.append(line)
return return_config
def get_section_from_config(config, section):
record = False
start_line = ""
end_line = ""
return_config = ""
with open(config, 'r') as f:
for index, line in enumerate(f):
if line.startswith(section):
start_line = index
return_config += line
record = True
continue
if record:
if line.startswith('listen') or line.startswith('frontend') or line.startswith('backend') or line.startswith('cache') or line.startswith('defaults') or line.startswith('global'):
record = False
end_line = index
end_line = end_line - 1
else:
return_config += line
return start_line, end_line, return_config
def rewrite_section(start_line, end_line, config, section):
record = False
start_line = int(start_line)
end_line = int(end_line)
return_config = ""
with open(config, 'r') as f:
for index, line in enumerate(f):
index = int(index)
if index == start_line:
record = True
return_config += section
continue
if index == end_line:
record = False
continue
if record:
continue
return_config += line
return return_config
def install_haproxy(serv, **kwargs):
import sql
script = "install_haproxy.sh"
@ -484,15 +544,18 @@ def show_backends(serv, **kwargs):
haproxy_sock_port = sql.get_setting('haproxy_sock_port')
cmd='echo "show backend" |nc %s %s' % (serv, haproxy_sock_port)
output, stderr = subprocess_execute(cmd)
ret = ""
if kwargs.get('ret'):
ret = list()
else:
ret = ""
for line in output:
if "#" in line or "stats" in line or "MASTER" in line:
continue
if line != "":
if len(line) > 1:
back = json.dumps(line).split("\"")
if kwargs.get('ret'):
ret += back[1]
ret += "<br />"
ret.append(back[1])
#ret += ","
else:
print(back[1], end="<br>")

View File

@ -122,6 +122,7 @@ if form.getvalue('logout'):
print("Set-cookie: uuid=; expires=Wed May 18 03:33:20 2003; path=/app/; httponly")
print("Content-type: text/html\n")
print('<meta http-equiv="refresh" content="0; url=/app/login.py">')
sys.exit()
if login is not None and password is not None:

View File

@ -72,6 +72,11 @@ async def async_get_overviewServers(serv1, serv2, desc):
cmd = 'echo "show info" |nc %s %s |grep -e "Ver\|CurrConns\|SessRate\|Maxco\|MB\|Uptime:"' % (serv2, haproxy_sock_port)
out = funct.subprocess_execute(cmd)
out1 = ""
hap_configs_dir = funct.get_config_var('configs', 'haproxy_save_configs_dir')
cfg = hap_configs_dir + serv2 + "-" + funct.get_data('config') + ".cfg"
funct.get_config(serv2, cfg)
backends = funct.get_sections(cfg)
os.system("/bin/rm -f " + cfg)
for k in out:
if "Ncat: Connection refused." not in k:
@ -80,7 +85,9 @@ async def async_get_overviewServers(serv1, serv2, desc):
out1 += "<br />"
else:
out1 = "Can\'t connect to HAproxy"
server_status = (serv1,serv2, out1, funct.ssh_command(serv2, commands),funct.show_backends(serv2, ret=1), desc)
# server_status = (serv1,serv2, out1, funct.ssh_command(serv2, commands),funct.show_backends(serv2, ret=1), desc)
server_status = (serv1,serv2, out1, funct.ssh_command(serv2, commands),backends, desc)
return server_status
async def get_runner_overviewServers():
@ -114,7 +121,7 @@ def get_map(serv):
cfg = hap_configs_dir + serv + "-" + date + ".cfg"
print('<center>')
print("<h3>Map from %s</h3><br />" % serv)
print("<h4>Map from %s</h4><br />" % serv)
G = nx.DiGraph()

111
app/sections.py Normal file
View File

@ -0,0 +1,111 @@
#!/usr/bin/env python3
import cgi
import os
import http.cookies
import funct
import sql
from jinja2 import Environment, FileSystemLoader
env = Environment(loader=FileSystemLoader('templates/'), autoescape=True)
template = env.get_template('sections.html')
print('Content-type: text/html\n')
funct.check_login()
form = cgi.FieldStorage()
serv = form.getvalue('serv')
section = form.getvalue('section')
sections = ""
config_read = ""
cfg = ""
stderr = ""
error = ""
aftersave = ""
start_line = ""
end_line = ""
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)
role = sql.get_user_role_by_uuid(user_id.value)
except:
pass
hap_configs_dir = funct.get_config_var('configs', 'haproxy_save_configs_dir')
if serv is not None and open is not None:
cfg = hap_configs_dir + serv + "-" + funct.get_data('config') + ".cfg"
error = funct.get_config(serv, cfg)
sections = funct.get_sections(cfg)
if serv is not None and section is not None :
try:
funct.logging(serv, "sections.py open config")
except:
pass
start_line, end_line, config_read = funct.get_section_from_config(cfg, section)
os.system("/bin/mv %s %s.old" % (cfg, cfg))
if serv is not None and form.getvalue('config') is not None:
try:
funct.logging(serv, "config.py edited config")
except:
pass
config = form.getvalue('config')
oldcfg = form.getvalue('oldconfig')
save = form.getvalue('save')
start_line = form.getvalue('start_line')
end_line = form.getvalue('end_line')
aftersave = 1
config = funct.rewrite_section(start_line, end_line, oldcfg, config)
try:
with open(cfg, "w") as conf:
conf.write(config)
except IOError:
error = "Can't read import config file"
MASTERS = sql.is_master(serv)
for master in MASTERS:
if master[0] != None:
funct.upload_and_restart(master[0], cfg, just_save=save)
stderr = funct.upload_and_restart(serv, cfg, just_save=save)
funct.diff_config(oldcfg, cfg)
#if save:
# c = http.cookies.SimpleCookie(os.environ.get("HTTP_COOKIE"))
# c["restart"] = form.getvalue('serv')
# print(c)
os.system("/bin/rm -f " + hap_configs_dir + "*.old")
template = template.render(h2 = 1, title = "Working with HAProxy configs",
role = role,
action = "sections.py",
user = user,
select_id = "serv",
serv = serv,
aftersave = aftersave,
config = config_read,
cfg = cfg,
selects = servers,
stderr = stderr,
error = error,
start_line = start_line,
end_line = end_line,
section = section,
sections = sections,
note = 1,
versions = funct.versions(),
token = token)
print(template)

View File

@ -677,7 +677,7 @@ def select_options(**kwargs):
def update_options(option, id):
con, cur = create_db.get_cur()
sql = """ update options set
`option` = '%s',
options = '%s'
where id = '%s' """ % (option, id)
try:
cur.execute(sql)
@ -1483,9 +1483,9 @@ if form.getvalue('newtoption'):
if form.getvalue('updateoption') is not None:
option = form.getvalue('updateoption')
id = form.getvalue('optionid')
id = form.getvalue('id')
print('Content-type: text/html\n')
if token is None or chanel is None or group is None:
if option is None or id is None:
print(error_mess)
else:
update_options(option, id)

View File

@ -16,7 +16,7 @@
<div id="listen">
<form name="add-listner" action="/app/add.py">
<table class="add-table">
<caption><h3 style="margin-left: 20px; margin-bottom: 10px;">Add listen</h3></caption>
<caption><h3>Add listen</h3></caption>
<tr>
<td class="addName">Select server: </td>
<td class="addOption">
@ -28,7 +28,7 @@
</select>
<div class="tooltip tooltipTop"><b>Note:</b> If you reconfigure Master server, Slave will reconfigured automatically</div>
</td>
<td rowspan="5" class="add-note addName">
<td rowspan="5" class="add-note addName alert-info">
A "listen" section defines a complete proxy with its frontend and backend parts combined in one section. It is generally useful for TCP-only traffic.
<br /><br />
All proxy names must be formed from upper and lower case letters, digits,
@ -242,7 +242,7 @@
<div id="frontend">
<form name="add-frontend" action="/app/add.py">
<table>
<caption><h3 style="margin-left: 20px; margin-bottom: 10px;">Add frontend</h3></caption>
<caption><h3>Add frontend</h3></caption>
<tr>
<td class="addName">Select server: </td>
<td class="addOption">
@ -254,7 +254,7 @@
</select>
<div class="tooltip tooltipTop"><b>Note:</b> If you reconfigure Master server, Slave will reconfigured automatically</div>
</td>
<td rowspan="5" class="add-note addName">
<td rowspan="5" class="add-note addName alert-info">
A "frontend" section describes a set of listening sockets accepting client connections.
<br /><br />
All proxy names must be formed from upper and lower case letters, digits,
@ -387,7 +387,7 @@
<div id="backend">
<form name="add-backend" action="/app/add.py">
<table>
<caption><h3 style="margin-left: 20px; margin-bottom: 10px;">Add backend</h3></caption>
<caption><h3>Add backend</h3></caption>
<tr>
<td class="addName">Select server: </td>
<td class="addOption">
@ -399,7 +399,7 @@
</select>
<div class="tooltip tooltipTop"><b>Note:</b> If you reconfigure Master server, Slave will reconfigured automatically</div>
</td>
<td rowspan="4" class="add-note addName">
<td rowspan="4" class="add-note addName alert-info">
A "backend" section describes a set of servers to which the proxy will connect to forward incoming connections.
<br /><br />
All proxy names must be formed from upper and lower case letters, digits,
@ -427,11 +427,11 @@
<option value="tcp">tcp</option>
</select>
<span id="https-backend-span">
<label for="https-backend" style="margin-top: 5px;">Ssl enabled on frontend?</label>
<label for="https-backend" style="margin-top: 5px;">SSL enabled on frontend?</label>
<input type="checkbox" id="https-backend" name="ssl" value="https">
</span>
<div id="https-hide-backend" style="display: none;">
<label for="ssl-check" style="margin-top: 5px;">Disable ssl verify on servers?</label><input type="checkbox" id="ssl-check" name="ssl-check" value="ssl-check" checked>
<label for="ssl-check" style="margin-top: 5px;">Disable SSL verify on servers?</label><input type="checkbox" id="ssl-check" name="ssl-check" value="ssl-check" checked>
</div>
</td>
</tr>
@ -580,7 +580,7 @@
<div id="ssl">
<table>
<tr class="overviewHead">
<td class="padding10 first-collumn" style="width: 20%;">View certificates</td>
<td class="padding10 first-collumn" style="width: 30%;">View certificates</td>
<td>
Exist certificates
</td>
@ -601,7 +601,7 @@
</tr>
<table>
<tr class="overviewHead">
<td class="padding10 first-collumn" style="width: 20%;">Upload SSL certificates</td>
<td class="padding10 first-collumn" style="width: 30%;">Upload SSL certificates</td>
<td>
Certificate name
</td>
@ -642,8 +642,8 @@
<td class="padding10 first-collumn">
{{ option.0 }}
</td>
<td class="padding10 first-collumn">
<input type="text" id="option-{{ option.0 }}" value="{{ option.1 }}" size="100" class="form-control">
<td class="padding10 first-collumn" style="width: 100%;">
<input type="text" id="option-body-{{ option.0 }}" value="{{ option.1 }}" size="100" class="form-control">
</td>
<td>
<a class="delete" onclick="confirmDeleteOption({{ option.0 }})" title="Delete option {{option.1}}" style="cursor: pointer;"></a>
@ -674,6 +674,9 @@
</tr>
</table>
<div id="ajax-option">
<div class="add-note addName alert-info" style="width: inherit; margin-right: 15px;">
In this section you can create, edit and delete options with given parameters. And after use them as autocomplete in the "Add" sections
</div>
</div>
{% if add %}
<div class="alert alert-success">
@ -688,7 +691,8 @@
<center><pre id="dialog-confirm-body"></pre></center>
</div>
<input type="hidden" id="group" value="{{ group }}">
</div>
</div>
<script>
$( ".force_close" ).selectmenu({
width: 180

View File

@ -1,10 +1,8 @@
<center>
<h3>Config from {{serv}}</h3>
<h4>Config from {{serv}}</h4>
<p class="accordion-expand-holder">
<a class="accordion-expand-all ui-button ui-widget ui-corner-all" href="#">Expand all</a>
{% if not view %}
<a class="ui-button ui-widget ui-corner-all" title="Edit this run config" target="_blank" href="versions.py?serv={{serv}}&open=open">Edit</a>
{% endif %}
<a class="ui-button ui-widget ui-corner-all" title="Edit this run config" href="config.py?serv={{serv}}&open=open">Edit</a>
<a class="accordion-expand-all ui-button ui-widget ui-corner-all" href="#">Expand all</a>
<button id="raw">Raw</button>
<button id="according" style="display: none;">According</button>
</p>
@ -24,23 +22,53 @@
{% endif %}
{% endif %}
{% if line.startswith('global') %}
<span class="param"> {{ line }} </span><div>
<span class="param">{{ line }}
{% if role <= 2 %}
<span class="accordion-link">
<a href="/app/sections.py?serv={{serv}}&section={{ line }}">Edit</a>
</span>
{% endif %}
</span><div>
{% continue %}
{% endif %}
{% if line.startswith('defaults') %}
</div><span class="param"> {{ line }} </span><div>
</div><span class="param">{{ line }}
{% if role <= 2 %}
<span class="accordion-link">
<a href="/app/sections.py?serv={{serv}}&section={{ line }}">Edit</a>
</span>
{% endif %}
</span><div>
{% continue %}
{% endif %}
{% if line.startswith('listen') %}
</div><span class="param"> {{ line }} </span><div>
</div><span class="param">{{ line }}
{% if role <= 2 %}
<span class="accordion-link">
<a href="/app/sections.py?serv={{serv}}&section={{ line }}">Edit</a>
</span>
{% endif %}
</span><div>
{% continue %}
{% endif %}
{% if line.startswith('frontend') %}
</div><span class="param"> {{ line }} </span><div>
</div><span class="param">{{ line }}
{% if role <= 2 %}
<span class="accordion-link">
<a href="/app/sections.py?serv={{serv}}&section={{ line }}">Edit</a>
</span>
{% endif %}
</span><div>
{% continue %}
{% endif %}
{% if line.startswith('backend') %}
</div><span class="param"> {{ line }} </span><div>
</div><span class="param"> {{ line }}
{% if role <= 2 %}
<span class="accordion-link">
<a href="/app/sections.py?serv={{serv}}&section={{ line }}">Edit</a>
</span>
{% endif %}
</span><div>
{% continue %}
{% endif %}
{% if line.startswith('cache') %}

View File

@ -3,8 +3,8 @@
<td class="padding10 first-collumn">
{{ option.0 }}
</td>
<td class="first-collumn">
<input type="text" id="option-{{option.0}}" class="form-control" size="100" value="{{option.1}}">
<td class="first-collumn" style="width: 100%;">
<input type="text" id="option-body-{{option.0}}" class="form-control" value="{{option.1}}">
</td>
<td>

View File

@ -3,9 +3,9 @@
<td class="overviewTr first-collumn">
<a name="{{ service.0 }}"></a>
{% if service.5 != "None" %}
<h3 title="IP {{ service.1 }} {{ service.5 }}"> {{ service.0 }} :</h3>
<h4 title="IP {{ service.1 }} {{ service.5 }}"> {{ service.0 }} :</h4>
{% else %}
<h3 title="IP {{ service.1 }}"> {{ service.0 }} :</h3>
<h4 title="IP {{ service.1 }}"> {{ service.0 }} :</h4>
{% endif %}
</td>
<td class="overviewTd" style="padding-top: 10px;">
@ -19,13 +19,17 @@
</pre>
</td>
<td style="padding: 10px; padding-bottom: 0;font-size: 12px;">
<pre style="padding-left: 0px; margin: 0;">
<span style="padding-left: 0px; margin: 0;">
{% if 'Unknown command' in service.4 %}
Too old version HAProxy
{% else %}
{{ service.4 }}
{% for s in service.4 %}
<a href="/app/sections.py?serv={{service.1}}&section={{ s }}" title="Edit {{s}} section" target="_blanck">
{{s}}
</a><br />
{% endfor %}
{% endif %}
</pre>
</span>
</td>
<td></td>
</tr>

View File

@ -1,9 +1,9 @@
<form action="diff.py#diff" method="get">
<center>
<h3>
<h4>
<span style="padding: 20px;">Choose left</span>
<span style="padding: 110px;">Choose right</span>
</h3>
</h4>
<p>
<select autofocus required name="left" id="left">
<option disabled selected>Choose version</option>

View File

@ -12,7 +12,6 @@
<script defer src="/inc/fa-solid.min.js"></script>
<script defer src="/inc/fontawesome.min.js"></script>
<link href="/inc/awesome.css" rel="stylesheet">
<!-- <link href="/inc/vertical_scrol/custom_scrollbar.css" rel="stylesheet"> -->
<link href="/inc/style.css" rel="stylesheet">
<link href="/inc/nprogress.css" rel="stylesheet">
<link rel="stylesheet" href="/inc/jquery-ui.css">
@ -21,41 +20,27 @@
<script src="/inc/js-cookie.js"></script>
<script src="/inc/script.js"></script>
<script src="/inc/nprogress.js"></script>
<!-- <script src="/inc/vertical_scrol/custom_scrollbar.min.js"></script> -->
</head>
<body>
<input type="hidden" id="token" value="{{ token }}">
<a name="top"></a>
<div class="show_menu" style="display: none;">
<a href="#" id="show_menu" title="Show menu" style="margin-top: 30px;position: absolute;">
<span class="ui-state-default ui-corner-all">
<span class="ui-icon ui-icon-arrowthick-1-e" id="arrow"></span>
</span>
</a>
</div>
<div class="top-menu">
<div class="LogoText">
<span id="logo_text" style="padding: 10px;">HAproxy-WI</span>
<a href="#" id="hide_menu" title="Hide menu" style="margin-left: 24px;position: absolute;">
<span class="ui-state-default ui-corner-all">
<span class="ui-icon ui-icon-arrowthick-1-w" id="arrow"></span>
</span>
</a>
<span id="logo_text">HAproxy-WI</span>
</div>
<div id="top-link" class="top-link">
<nav id="menu">
<ul class="menu">
<li class="p_menu"><a title="Statistics, monitoring and logs" class="stats">Stats</a>
{% if user %}
<li><a href=/app/overview.py title="Server and service status" class="overview-link">Overview</a></li>
<li class="p_menu"><a title="Statistics, monitoring and logs" class="stats">Monitoring</a>
<ul class="v_menu">
<li><a href=/app/overview.py title="Server and service status" class="overview-link head-submenu">Overview</a></li>
<li><a href=/app/viewsttats.py title="Show stats" class="stats head-submenu">Stats</a></li>
<li><a href=/app/logs.py title="View logs" class="logs head-submenu"> Logs</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="metrics head-submenu">Metrics</a></li>
</ul>
</li>
<li class="p_menu"><a title="Actions with Haproxy configs" class="config-show">Haproxy</a>
{% if user %}
<li class="p_menu"><a title="Actions with Haproxy configs" class="config-show">Haproxy</a>
<ul class="v_menu">
<li><a href=/app/config.py title="Working with Haproxy Configs" class="edit head-submenu">Configs</a> </li>
{% if role <= 2 %}
@ -229,6 +214,25 @@
<div>
There is a new version HAProxy-WI. Check the <a href="/app/update.py">Update page</a>
</div>
</div>
</div>
<div class="footer">
<a href="#" id="hide_menu" title="Hide menu" style="float: left;">
<span class="ui-state-default ui-corner-all">
<span class="ui-icon ui-icon-arrowthick-1-w" id="arrow"></span>
</span>
</a>
<div class="show_menu" style="display: none; float: left;">
<a href="#" id="show_menu" title="Show menu">
<span class="ui-state-default ui-corner-all">
<span class="ui-icon ui-icon-arrowthick-1-e" id="arrow"></span>
</span>
</a>
</div>
<div class="footer-div">
<a href="https://github.com/Aidaho12/haproxy-wi/issues" class="footer-link" target="_blank">Help</a>
<a href="https://github.com/Aidaho12" class="footer-link" target="_blank">Contact</a>
<a href="http://haproxy-wi.org" class="footer-link" target="_blank">About</a>
</div>
</div>
</body>
</html>

View File

@ -27,15 +27,14 @@
{% endif %}
{% endfor %}
</select>
{% if role <= 2 %}
<button type="submit" value="open" name="open" class="btn btn-default" title="Edit running config">Edit</button>
{% endif %}
{% if not keepalived %}
<a class="ui-button ui-widget ui-corner-all" title="Show running config" onclick="showConfig()">Show</a>
<a class="ui-button ui-widget ui-corner-all" title="Show running config" onclick="showConfig()">Open</a>
<a class="ui-button ui-widget ui-corner-all" title="Compare configs" onclick="showCompareConfigs()">Compare</a>
<a class="ui-button ui-widget ui-corner-all" title="Show map" onclick="showMap()">Map</a>
<a class="ui-button ui-widget ui-corner-all" title="View stat" onclick="openStats()">Stat</a>
<a class="ui-button ui-widget ui-corner-all" title="Show verisons" onclick="openVersions()">Verisons</a>
{% if role <= 2 %}
<a class="ui-button ui-widget ui-corner-all" title="Show verisons" onclick="openVersions()">Verisons</a>
{% endif %}
{% endif %}
</form>
</p>
@ -53,10 +52,7 @@
{% if config %}
{% if role <= 2 %}
<div id="config">
{% if note %}
<div class="alert alert-info"><b>Note:</b> If you reconfigure Master server, Slave will reconfigured automatically</div>
{% endif %}
<h3>Config from {{ serv }}</h3>
<h4>Config from {{ serv }}</h4>
<form action="{{ action }}" name="saveconfig" method="get">
<input type="hidden" value="{{ serv }}" name="serv">
<input type="hidden" value="{{ cfg }}.old" name="oldconfig">
@ -67,6 +63,9 @@
<button type="submit" value="" name="" class="btn btn-default">Save and restart</button>
</p>
</form>
{% if note %}
<div class="alert alert-info"><b>Note:</b> If you reconfigure Master server, Slave will reconfigured automatically</div>
{% endif %}
</div>
{% endif %}
{% endif %}

View File

@ -33,7 +33,7 @@
{% endif %}
{% if open %}
<center>
<h3>Choose old version</h3>
<h4>Choose old version</h4>
<form action="configver.py#conf" method="get">
<p>
<select autofocus required name="configver" id="configver">

View File

@ -22,7 +22,7 @@
{% endif %}
{% if open %}
<center>
<h3>Choose old version</h3>
<h4>Choose old version</h4>
<form action="versions.py#conf" method="get">
<label for="select_all" id="label_select_all"><b>Select all</b></label>
<input type="checkbox" id="select_all"><br />

View File

@ -2,7 +2,7 @@
{% block content %}
<script src="/inc/users.js"></script>
<table class="overview">
<caption><h3 style="margin-left: 20px; margin-bottom: 10px;">Create new HA cluster</h3></caption>
<caption><h3>Create new HA cluster</h3></caption>
<tr class="overviewHead">
<td class="padding10 first-collumn">Master</td>
<td>Slave</td>
@ -48,7 +48,7 @@
</table>
<table>
<caption><h3 style="margin-left: 20px; margin-bottom: 10px;">Or add VRRP to exist</h3></caption>
<caption><h3>Or add VRRP to exist</h3></caption>
<tr class="overviewHead">
<td class="padding10 first-collumn">Master</td>
<td>Slave</td>

View File

@ -30,6 +30,9 @@
<input type="hidden" id="group" value="{{group}}">
</table>
<div id="ajax"></div>
<div class="add-note addName alert-info" style="width: inherit; margin-right: 15px;">
In this section you can create and edit black and white lists. And after use them in the HAProxy configs
</div>
<div id="dialog-confirm" title="View certificate " style="display: none;">
<span><b>Note:</b>Each new address should be specified from a new line</span>
<textarea id="edit_lists" cols=95 rows=20></textarea>

View File

@ -0,0 +1,63 @@
{% extends "base.html" %}
{% block content %}
<center>
<h3>Choose a section</h3>
<p>
<form action="{{ action }}" method="get">
<select autofocus required name="section" id="{{ select_id }}">
<option disabled>Choose a section</option>
{% for s in sections %}
{% if s == section %}
<option value="{{ s }}" selected>{{ s }}</option>
{% else %}
<option value="{{ s }}">{{ s }}</option>
{% endif %}
{% endfor %}
</select>
<input type="hidden" value="{{ serv }}" name="serv">
{% if role <= 2 %}
<button type="submit" value="open" name="open" class="btn btn-default" title="Edit running config">Edit</button>
{% endif %}
</form>
</p>
{% if config %}
{% if role <= 2 %}
<div id="config">
<h4>You are editting "{{section}}" from server {{ serv }}</h4>
<form action="{{ action }}" name="saveconfig" method="get">
<input type="hidden" value="{{ serv }}" name="serv">
<input type="hidden" value="{{ start_line }}" name="start_line">
<input type="hidden" value="{{ end_line }}" name="end_line">
<input type="hidden" value="{{ cfg }}.old" name="oldconfig">
<textarea name="config" class="config" rows="35" cols="80" style="height: 40%">{{ config }}</textarea>
<p>
<button type="submit" value="test" name="save" class="btn btn-default">Just test</button>
<button type="submit" value="save" name="save" class="btn btn-default">Just save</button>
<button type="submit" value="" name="" class="btn btn-default">Save and restart</button>
</p>
</form>
{% if note %}
<div class="alert alert-info"><b>Note:</b> If you reconfigure Master server, Slave will reconfigured automatically</div>
{% endif %}
</div>
{% endif %}
{% endif %}
{% if aftersave %}
<div class="alert alert-info">New config was saved as: {{ cfg }} </div>
{% if stderr or error %}
<div class="alert alert-danger">
Some errors:
<br>
<br>
{{stderr}}
{{error}}
</div>
{% else %}
<div class="alert alert-success">Config ok</div>
<a href="viewsttats.py?serv={{ serv }}" target="_blank" title="View stats">Go to view stats</a>
{% endif %}
<script>window.history.pushState("Config", "Config", cur_url[0])</script>
{% endif %}
</center>
{% endblock %}

View File

@ -17,7 +17,7 @@
{% set section = namespace(section='') %}
{% for set in settings %}
{% if section.section|string() != set.2|string() %}
<th><h3 style="margin-left: 20px; margin-bottom: 10px;">{{ set.2 }} section</h3></th>
<th colspan="3"><h3>{{ set.2 }} section</h3></th>
{% endif %}
{% set section.section = set.2 %}
<tr class="{{ loop.cycle('odd', 'even') }}">

View File

@ -21,7 +21,7 @@
{% endif %}
</td>
</table>
<div class="add-note addName" style="width: inherit;">
<div class="add-note addName alert-info" style="width: inherit; margin-right: 15px;">
<b style="font-size: 20px; display: block; padding-bottom: 10px;">Note:</b>
For update you have to use HAProxy-WI repository. If do not use repositiry then use update.sh script in HAProxy-WI home directory <br />
<br />
@ -30,6 +30,6 @@
<br />
Read more about update in <a href="https://haproxy-wi.org/updates.py" title="Doc" target="_blank">docs</a>
and <a href="https://haproxy-wi.org/changelog.py" title="Changelog" target="_blank">changelog</a>
</div>
</div>
<div id="ajax"></div>
{% endblock %}

View File

@ -18,7 +18,7 @@
<div id="ajax" style="margin-left: 5px; margin-right: 5px;"></div>
<div id="notice" style="padding-left: 15px; font-size: 25px;">
Please choose a server
</div>
</div>
<script>
if (cur_url[1]) {
showStats();
@ -34,9 +34,13 @@
$('#notice').hide();
$('li').css('margin-top', '0');
$('li').css('width', '207px ');
$('li').css('padding', '0px');
$('li').css('margin', '0px');
$('.menu li ul li').css('width', '227px');
$('.menu li ul li').css('margin-left', '-20px');
$('th').css('background-color', '#f5faf4');
$('table.tbl th.pxname').css('background-color', '#5d9ceb');
$('.v_menu').css('left', '200px');
$('table.tbl th.pxname').css('width', '100%');
$('a.px:link').css('color', '#fff');
$('td').css('font-family', '"Helvetica Neue", Helvetica, Arial, sans-serif');

View File

@ -47,5 +47,9 @@ $( function() {
expandLink.text(isAllOpen? 'Collapse All': 'Expand all')
.data('isAllOpen', isAllOpen);
});
$(".accordion-link a").on("click", function(event) {
window.location.href = $(this).attr("href");
event.preventDefault();
});
})

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -3,6 +3,22 @@ var cur_url = window.location.href.split('/').pop();
cur_url = cur_url.split('?');
var intervalId;
$( function() {
$('.menu li ul li').each(function () {
var link = $(this).find('a').attr('href');
var link2 = link.split('/')[2]
if (cur_url[0] == link2) {
$(this).parent().css('display', 'contents');
$(this).parent().css('top', '0');
$(this).parent().css('left', '0');
$(this).parent().children().css('margin-left', '-20px');
$(this).parent().find('a').css('padding-left', '20px');
$(this).find('a').css('padding-left', '30px');
$(this).find('a').css('border-left', '4px solid #5D9CEB');
}
});
});
jQuery.expr[':'].regex = function(elem, index, match) {
var matchParams = match[3].split(','),
validLabels = /^(data|css):/,
@ -462,16 +478,6 @@ $( function() {
$( "input[type=checkbox]" ).checkboxradio();
$( ".controlgroup" ).controlgroup();
var location = window.location.href;
var cur_url = '/app/' + location.split('/').pop();
cur_url = cur_url.split('?');
// $('.menu li').each(function () {
// var link = $(this).find('a').attr('href');
// if (cur_url[0] == link) {
// $(this).addClass('current');
// }
// });
var now = new Date(Date.now());
var date1 = now.getHours() * 60 - 1 * 60;
var date2 = now.getHours() * 60 + now.getMinutes();
@ -750,15 +756,21 @@ $( function() {
$( "#hide_menu" ).click(function() {
$(".top-menu").hide( "drop", "fast" );
$(".container").css("max-width", "98%");
$(".footer").css("max-width", "98%");
$(".container").css("margin-left", "1%");
$(".footer").css("margin-left", "1%");
$(".show_menu").show();
$("#hide_menu").hide();
Cookies.set('hide_menu', 'hide', { expires: 365 });
});
$( "#show_menu" ).click(function() {
$(".top-menu").show( "drop", "fast" );
$(".container").css("max-width", "91%");
$(".footer").css("max-width", "91%");
$(".container").css("margin-left", "207px");
$(".footer").css("margin-left", "207px");
$(".show_menu").hide();
$("#hide_menu").show();
Cookies.set('hide_menu', 'show', { expires: 365 });
});
@ -888,6 +900,19 @@ $( function() {
autoFocus: true,
minLength: -1
});
$( "#new-option" ).autocomplete({
source: availableTags,
autoFocus: true,
minLength: -1,
select: function( event, ui ) {
$("#new-option").append(ui.item.value + " ")
}
});
$( "#option_table input" ).change(function() {
var id = $(this).attr('id').split('-');
updateOptions(id[2])
console.log(id)
});
$( "#options" ).autocomplete({
source: availableTags,
autoFocus: true,
@ -1141,7 +1166,9 @@ $( function() {
$( "#blacklist-hide-input1" ).prop('required',false);
}
});
var location = window.location.href;
var cur_url = '/app/' + location.split('/').pop();
cur_url = cur_url.split('?');
cur_url = cur_url[0].split('#');
if (cur_url[0] == "/app/add.py") {
$("#cache").checkboxradio( "disable" );
@ -1162,97 +1189,122 @@ $( function() {
$( "#serv3" ).on('selectmenuchange',function() {
change_select_acceleration("3");
});
$( "#add1" ).on( "click", function() {
$('.menu li').each(function () {
$(this).removeClass('current');
$('.menu li ul li').each(function () {
$(this).find('a').css('padding-left', '20px')
$(this).find('a').css('border-left', '0px solid #5D9CEB');
$(this).children("#add1").css('padding-left', '30px');
$(this).children("#add1").css('border-left', '4px solid #5D9CEB');
});
$(this).parent().addClass('current');
$( "#tabs" ).tabs( "option", "active", 0 );
} );
$( "#add2" ).on( "click", function() {
$('.menu li').each(function () {
$(this).removeClass('current');
$('.menu li ul li').each(function () {
$(this).find('a').css('padding-left', '20px')
$(this).find('a').css('border-left', '0px solid #5D9CEB');
$(this).children("#add2").css('padding-left', '30px');
$(this).children("#add2").css('border-left', '4px solid #5D9CEB');
});
$(this).parent().addClass('current');
$( "#tabs" ).tabs( "option", "active", 1 );
} );
$( "#add3" ).on( "click", function() {
$('.menu li').each(function () {
$(this).removeClass('current');
$('.menu li ul li').each(function () {
$(this).find('a').css('padding-left', '20px')
$(this).find('a').css('border-left', '0px solid #5D9CEB');
$(this).children("#add3").css('padding-left', '30px');
$(this).children("#add3").css('border-left', '4px solid #5D9CEB');
});
$(this).parent().addClass('current');
$( "#tabs" ).tabs( "option", "active", 2 );
} );
$( "#add4" ).on( "click", function() {
$('.menu li').each(function () {
$(this).removeClass('current');
$('.menu li ul li').each(function () {
$(this).find('a').css('padding-left', '20px')
$(this).find('a').css('border-left', '0px solid #5D9CEB');
$(this).children("#add4").css('padding-left', '30px');;
$(this).children("#add4").css('border-left', '4px solid #5D9CEB');
});
$(this).parent().addClass('current');
$( "#tabs" ).tabs( "option", "active", 3 );
} );
$( "#add5" ).on( "click", function() {
$('.menu li').each(function () {
$(this).removeClass('current');
$('.menu li ul li').each(function () {
$(this).find('a').css('padding-left', '20px')
$(this).find('a').css('border-left', '0px solid #5D9CEB');
$(this).children("#add5").css('padding-left', '30px');;
$(this).children("#add5").css('border-left', '4px solid #5D9CEB');
});
$(this).parent().addClass('current');
$( "#tabs" ).tabs( "option", "active", 4 );
} );
}
if (cur_url[0] == "/app/users.py" || cur_url[0] == "/app/servers.py") {
$( ".users" ).on( "click", function() {
$('.menu li').each(function () {
$(this).removeClass('current');
$('.menu li ul li').each(function () {
$(this).find('a').css('padding-left', '20px')
$(this).find('a').css('border-left', '0px solid #5D9CEB');
$(this).children(".users").css('padding-left', '30px');
$(this).children(".users").css('border-left', '4px solid #5D9CEB');
});
$(this).parent().addClass('current');
$( "#tabs" ).tabs( "option", "active", 0 );
} );
if (cur_url[0] == "/app/users.py") {
$( ".group" ).on( "click", function() {
$('.menu li').each(function () {
$(this).removeClass('current');
if (cur_url[0] == "/app/users.py") {
$( ".group" ).on( "click", function() {
$('.menu li ul li').each(function () {
$(this).find('a').css('padding-left', '20px')
$(this).find('a').css('border-left', '0px solid #5D9CEB');
$(this).children(".group").css('padding-left', '30px');
$(this).children(".group").css('border-left', '4px solid #5D9CEB');
});
$(this).parent().addClass('current');
$( "#tabs" ).tabs( "option", "active", 1 );
} );
} else {
$( ".runtime" ).on( "click", function() {
$('.menu li').each(function () {
$(this).removeClass('current');
$( "#tabs" ).tabs( "option", "active", 1 );
} );
} else {
$( ".runtime" ).on( "click", function() {
$('.menu li ul li').each(function () {
$(this).find('a').css('padding-left', '20px')
$(this).find('a').css('border-left', '0px solid #5D9CEB');
$(this).children(".runtime").css('padding-left', '30px');
$(this).children(".runtime").css('border-left', '4px solid #5D9CEB');
});
$(this).parent().addClass('current');
$( "#tabs" ).tabs( "option", "active", 1 );
} );
}
$( "#tabs" ).tabs( "option", "active", 1 );
} );
}
if (cur_url[0] == "/app/servers.py") {
$( ".admin" ).on( "click", function() {
$('.menu li').each(function () {
$(this).removeClass('current');
});
$(this).parent().addClass('current');
$('.menu li ul li').each(function () {
$(this).find('a').css('padding-left', '20px')
$(this).find('a').css('border-left', '0px solid #5D9CEB');
$(this).children(".admin").css('padding-left', '30px');
$(this).children(".admin").css('border-left', '4px solid #5D9CEB');
});
$( "#tabs" ).tabs( "option", "active", 2 );
} );
}
if (cur_url[0] == "/app/users.py") {
$( ".runtime" ).on( "click", function() {
$('.menu li').each(function () {
$(this).removeClass('current');
});
$(this).parent().addClass('current');
$('.menu li ul li').each(function () {
$(this).find('a').css('border-left', '0px solid #5D9CEB');
$(this).find('a').css('padding-left', '20px')
$(this).children(".runtime").css('padding-left', '30px');
$(this).children(".runtime").css('border-left', '4px solid #5D9CEB');
});
$( "#tabs" ).tabs( "option", "active", 2 );
} );
}
$( ".role" ).on( "click", function() {
$('.menu li').each(function () {
$(this).removeClass('current');
$('.menu li ul li').each(function () {
$(this).find('a').css('border-left', '0px solid #5D9CEB');
$(this).find('a').css('padding-left', '20px')
$(this).children(".role").css('padding-left', '30px');
$(this).children(".role").css('border-left', '4px solid #5D9CEB');
});
$(this).parent().addClass('current');
$( "#tabs" ).tabs( "option", "active", 3 );
} );
$( ".admin" ).on( "click", function() {
$('.menu li').each(function () {
$(this).removeClass('current');
$('.menu li ul li').each(function () {
$(this).find('a').css('border-left', '0px solid #5D9CEB');
$(this).find('a').css('padding-left', '20px')
$(this).children(".admin").css('padding-left', '30px');
$(this).children(".admin").css('border-left', '4px solid #5D9CEB');
});
$(this).parent().addClass('current');
$( "#tabs" ).tabs( "option", "active", 4 );
} );
}
@ -1450,6 +1502,33 @@ $( function() {
showUpdates.dialog('open');
});
});
function updateOptions(id) {
$('#error').remove();
$.ajax( {
url: "sql.py",
data: {
updateoption: $('#option-body-'+id).val(),
id: id
},
type: "GET",
success: function( data ) {
data = data.replace(/\s+/g,' ');
if (data.indexOf('error') != '-1') {
$("#ajax-ssh").append(data);
$('#errorMess').click(function() {
$('#error').remove();
$('.alert-danger').remove();
});
} else {
$('.alert-danger').remove();
$("#option-"+id).addClass( "update", 1000 );
setTimeout(function() {
$( "#option-"+id ).removeClass( "update" );
}, 2500 );
}
}
} );
}
function confirmDeleteOption(id) {
$( "#dialog-confirm-delete" ).dialog({
resizable: false,

View File

@ -2,13 +2,14 @@ html {
font-size: 10px;
}
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 14px;
font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;
font-size: 1.3em;
line-height: 1.42857143;
color: #000;
background-color: #eee;
margin: 0;
padding: 0;
overflow: auto;
}
h2 {
background: #5D9CEB;
@ -20,8 +21,12 @@ h2 {
margin-bottom: 0px;
}
h3 {
margin-top: 10px;
margin-top: -0;
margin-bottom: 0px;
background: #d1ecf1;
padding: 0.3em;
font-size: 1.6em;
border-bottom: 1px solid #ddd;
}
form {
margin: 0;
@ -40,8 +45,8 @@ pre {
cursor: pointer;
}
.top-menu {
position: fixed;
height: 100%;
position: absolute;
height: 110%;
width: 207px;
float: left;
margin-bottom: 20px;
@ -51,7 +56,7 @@ pre {
z-index: 1000;
display: block;
}
.top-menu, .footer {
.top-menu {
background-color: #292e34;
}
.logoText {
@ -63,7 +68,10 @@ pre {
border-bottom: 1px solid aliceblue;
padding-left: 20px;
padding-top: 2px;
padding-bottom: 3px;
}
#logo_text {
display: block;
margin-top: -4px;
}
.top-menu img {
max-width: 125px;
@ -71,7 +79,7 @@ pre {
padding-left: 20px;
}
.container {
min-height: calc(99vh - 0px);
min-height: calc(99vh - 50px);
max-width: 91%;
min-width: 40%;
background-color: #fff;
@ -79,6 +87,39 @@ pre {
margin-right: 20px;
padding-bottom: 10px;
}
.footer {
min-height: 50px;
top: calc(99vh - 50px);
right: 0;
left: 0;
max-width: 91%;
min-width: 40%;
background-color: #fff;
margin-left: 207px;
margin-right: 20px;
border-top: 1px solid #ddd;
/* position: fixed; */
}
.footer-div {
display: block;
padding-top: 12px;
text-align: right;
margin-right: 20px;
}
.footer-link, .footer-copyright {
padding: 20px;
color: #5d9ceb;
font-size: 0.9em;
padding-top: 12px;
padding-right: 5px;
}
.footer-copyright {
color: #586069 ;
float: left;
margin-left: 10px;
}
#cover {
position: absolute;
display: none;
@ -158,14 +199,13 @@ pre {
}
.configShow, .diff {
margin-left: 16%;
//height: 78%;
overflow: auto;
width: 70%;
border: 1px solid #DCDCDC;
border-radius: 5px;
}
.config {
height: 70%;
height: 60%;
}
.diffHead {
background-color: #F5F5F5;
@ -228,6 +268,10 @@ pre {
.line:hover, .line3:hover {
background-color: #f6f8fa;
}
.accordion-link {
float: right;
margin-right: 1em;
}
.time-range {
border: 0;
background-color: #f5faf4;
@ -288,13 +332,6 @@ pre {
margin-bottom: -20px;
padding-top: 10px;
}
.footer {
box-shadow: 1px 1px 5px grey;
min-height: 50px;
top: 0;
right: 0;
left: 0;
}
.overview {
width: 100%;
}
@ -396,7 +433,7 @@ ul{
}
.menu {
min-height: calc(100vh - 95px);
font-size: 18px;
font-size: 1.1em;
}
.menu a{
background: #292e34;
@ -415,6 +452,8 @@ ul{
background: #48505A;
padding: 10px 0 10px 20px;
color: #fff;
border-left-color: #5D9CEB;
border-left: 4px solid #5D9CEB;
}
.menu li:first-child a, .menu li .v_menu li:first-child a{
border-radius: 3px 3px 0 0;
@ -507,6 +546,7 @@ ul{
.ui-tabs-nav {
border-radius: 0 !important;
padding-left: 25px !important;
padding-top: 0.28em !important;
}
.ui-tabs .ui-tabs-panel {
padding: 0 !important;
@ -532,6 +572,9 @@ ul{
.need-field {
color: red;
}
.ui-corner-all {
border-radius: 0 !important;
}
a {
background-color: transparent;
}
@ -624,13 +667,6 @@ a:focus {
outline: 5px auto -webkit-focus-ring-color;
outline-offset: -2px;
}
.container-fluid {
padding-right: 15px;
padding-left: 15px;
margin-right: auto;
margin-left: auto;
}
.row {
margin-right: -15px;
margin-left: -15px;
@ -642,7 +678,9 @@ a:focus {
padding:15px;
margin-bottom:20px;
border:1px solid transparent;
border-radius:4px
border-radius:4px;
width: 400px;
display: block;
}
.alert a {
cursor: pointer;
@ -651,16 +689,13 @@ a:focus {
margin-bottom: 10px;
}
.alert-danger, .alert-info, .alert-success, .alert-warning, .added {
width: 400px;
margin-left: 15px;
margin-top: 15px;
display: block;
margin-top: 15px;
}
.alert-danger {
color: #a94442;
background-color: #f2dede;
border-color: #ebccd1;
width: 400px;
margin-bottom: -50px;
}
.alert-success, .added{

View File

@ -167,6 +167,10 @@ $( function() {
$('.alert-danger').remove();
$('.alert-warning').remove();
$("#ajax").html('<div class="alert alert-danger">Cannot connect to HAProxy-WI repository. Connection timed out</data>');
} else if (data.indexOf('--disable') != '-1') {
$('.alert-danger').remove();
$('.alert-warning').remove();
$("#ajax").html('<div class="alert alert-danger">It is seems like you have problem with your repositorys.</data>');
}
}
} );