Pavel Loginov 2020-08-02 20:24:09 +02:00
parent e286b40998
commit eecfd6995f
9 changed files with 396 additions and 53 deletions

View File

@ -179,10 +179,9 @@ def return_ssh_keys_path(serv, **kwargs):
import sql
fullpath = get_config_var('main', 'fullpath')
ssh_enable = ''
ssh_port = ''
ssh_user_name = ''
ssh_user_password = ''
if kwargs.get('id'):
for sshs in sql.select_ssh(id=kwargs.get('id')):
ssh_enable = sshs[2]
@ -419,6 +418,7 @@ def get_all_stick_table():
cmd='echo "show table"|nc %s %s |awk \'{print $3}\' | tr -d \'\n\' | tr -d \'[:space:]\'' % (serv, haproxy_sock_port)
output, stderr = subprocess_execute(cmd)
return output[0]
def get_stick_table(table):
import sql

View File

@ -98,7 +98,6 @@ if form.getvalue('ip_select') is not None:
if form.getvalue('ipbackend') is not None and form.getvalue('backend_server') is None:
import sql
haproxy_sock_port = sql.get_setting('haproxy_sock_port')
backend = form.getvalue('ipbackend')
cmd='echo "show servers state"|nc %s %s |grep "%s" |awk \'{print $4}\'' % (serv, haproxy_sock_port, backend)
@ -111,7 +110,6 @@ if form.getvalue('ipbackend') is not None and form.getvalue('backend_server') is
if form.getvalue('ipbackend') is not None and form.getvalue('backend_server') is not None:
import sql
haproxy_sock_port = sql.get_setting('haproxy_sock_port')
backend = form.getvalue('ipbackend')
backend_server = form.getvalue('backend_server')
@ -121,7 +119,6 @@ if form.getvalue('ipbackend') is not None and form.getvalue('backend_server') is
if form.getvalue('backend_ip') is not None:
import sql
backend_backend = form.getvalue('backend_backend')
backend_server = form.getvalue('backend_server')
backend_ip = form.getvalue('backend_ip')
@ -166,7 +163,6 @@ if form.getvalue('maxconn_select') is not None:
if form.getvalue('maxconn_frontend') is not None:
import sql
frontend = form.getvalue('maxconn_frontend')
maxconn = form.getvalue('maxconn_int')
if form.getvalue('maxconn_int') is None:
@ -238,7 +234,6 @@ if form.getvalue('table_select') is not None:
if form.getvalue('ip_for_delete') is not None:
import sql
haproxy_sock_port = sql.get_setting('haproxy_sock_port')
ip = form.getvalue('ip_for_delete')
table = form.getvalue('table_for_delete')
@ -246,11 +241,90 @@ if form.getvalue('ip_for_delete') is not None:
cmd='echo "clear table %s key %s" |nc %s %s' % (table, ip, serv, haproxy_sock_port)
output, stderr = funct.subprocess_execute(cmd)
if stderr[0] != '':
print(stderr[0])
print('error: ' + stderr[0])
if form.getvalue('list_serv_select') is not None:
haproxy_sock_port = sql.get_setting('haproxy_sock_port')
cmd='echo "show acl"|nc %s %s |grep "loaded from" |awk \'{print $1,$2}\'' % (serv, haproxy_sock_port)
output, stderr = funct.subprocess_execute(cmd)
print(output)
if form.getvalue('list_select_id') is not None:
from jinja2 import Environment, FileSystemLoader
env = Environment(loader=FileSystemLoader('templates/'), autoescape=True, extensions=['jinja2.ext.loopcontrols', 'jinja2.ext.do'], trim_blocks=True, lstrip_blocks=True)
template = env.get_template('ajax/list.html')
list_id = form.getvalue('list_select_id')
list_name = form.getvalue('list_select_name')
haproxy_sock_port = sql.get_setting('haproxy_sock_port')
cmd='echo "show acl #%s"|nc %s %s' % (list_id, serv, haproxy_sock_port)
output, stderr = funct.subprocess_execute(cmd)
template = template.render(list=output, list_id=list_id, list_name=list_name)
print(template)
if form.getvalue('list_id_for_delete') is not None:
import http.cookies
haproxy_sock_port = sql.get_setting('haproxy_sock_port')
lists_path = sql.get_setting('lists_path')
fullpath = funct.get_config_var('main', 'fullpath')
ip_id = form.getvalue('list_ip_id_for_delete')
ip = form.getvalue('list_ip_for_delete')
list_id = form.getvalue('list_id_for_delete')
list_name = form.getvalue('list_name')
cookie = http.cookies.SimpleCookie(os.environ.get("HTTP_COOKIE"))
user_group = cookie.get('group')
user_group = user_group.value
cmd = "sed -i 's!%s$!!' %s/%s/%s/%s && sed -i '/^$/d' %s/%s/%s/%s" % (ip, fullpath, lists_path, user_group, list_name, fullpath, lists_path, user_group, list_name)
output, stderr = funct.subprocess_execute(cmd)
if output:
print('error: ' + str(output))
if stderr:
print('error: ' + str(stderr))
cmd='echo "del acl #%s #%s" |nc %s %s' % (list_id, ip_id, serv, haproxy_sock_port)
output, stderr = funct.subprocess_execute(cmd)
if output[0] != '':
print('error: ' + output[0])
if stderr[0] != '':
print('error: ' + stderr[0])
if form.getvalue('list_ip_for_add') is not None:
import http.cookies
haproxy_sock_port = sql.get_setting('haproxy_sock_port')
lists_path = sql.get_setting('lists_path')
fullpath = funct.get_config_var('main', 'fullpath')
ip = form.getvalue('list_ip_for_add')
list_id = form.getvalue('list_id_for_add')
list_name = form.getvalue('list_name')
cookie = http.cookies.SimpleCookie(os.environ.get("HTTP_COOKIE"))
user_group = cookie.get('group')
user_group = user_group.value
cmd = 'echo "%s" >> %s/%s/%s/%s' % (ip, fullpath, lists_path, user_group, list_name)
output, stderr = funct.subprocess_execute(cmd)
if output:
print('error: ' + str(output))
if stderr:
print('error: ' + str(stderr))
cmd = 'echo "add acl #%s %s" |nc %s %s' % (list_id, ip, serv, haproxy_sock_port)
output, stderr = funct.subprocess_execute(cmd)
if output[0]:
print('error: ' + output[0])
if stderr:
print('error: ' + stderr[0])
if form.getvalue("change_pos") is not None:
import sql
pos = form.getvalue('change_pos')
sql.update_server_pos(pos, serv)
@ -1049,11 +1123,11 @@ if form.getvalue('haproxy_exp_install'):
else:
proxy_serv = ''
commands = [ "chmod +x "+script +" && ./"+script +" PROXY=" + proxy_serv+
commands = ["chmod +x "+script +" && ./"+script +" PROXY=" + proxy_serv+
" STAT_PORT="+stats_port+" STAT_FILE="+server_state_file+
" SSH_PORT="+ssh_port+" STAT_PAGE="+stat_page+
" STATS_USER="+stats_user+" STATS_PASS="+stats_password+" HOST="+serv+
" USER="+ssh_user_name+" PASS="+ssh_user_password+" KEY="+ssh_key_name ]
" USER="+ssh_user_name+" PASS="+ssh_user_password+" KEY="+ssh_key_name]
output, error = funct.subprocess_execute(commands[0])
@ -1246,7 +1320,7 @@ if form.getvalue('metrics_hapwi_ram'):
cmd = "free -m |grep Mem |awk '{print $3,$4,$5,$6,$7}'"
metric, error = funct.subprocess_execute(cmd)
else:
commands = [ "free -m |grep Mem |awk '{print $3,$4,$5,$6,$7}'" ]
commands = ["free -m |grep Mem |awk '{print $3,$4,$5,$6,$7}'"]
metric, error = funct.subprocess_execute(commands[0])
for i in metric:
@ -1268,7 +1342,7 @@ if form.getvalue('metrics_hapwi_cpu'):
cmd = "top -b -n 1 |grep Cpu |awk -F':' '{print $2}'|awk -F' ' 'BEGIN{ORS=\" \";} { for (i=1;i<=NF;i+=2) print $i}'"
metric, error = funct.subprocess_execute(cmd)
else:
commands = [ "top -b -n 1 |grep Cpu |awk -F':' '{print $2}'|awk -F' ' 'BEGIN{ORS=\" \";} { for (i=1;i<=NF;i+=2) print $i}'" ]
commands = ["top -b -n 1 |grep Cpu |awk -F':' '{print $2}'|awk -F' ' 'BEGIN{ORS=\" \";} { for (i=1;i<=NF;i+=2) print $i}'"]
metric, error = funct.subprocess_execute(commands[0])
for i in metric:
@ -1339,7 +1413,7 @@ if form.getvalue('get_hap_v'):
if form.getvalue('get_nginx_v'):
cmd = [ '/usr/sbin/nginx -v' ]
cmd = ['/usr/sbin/nginx -v']
print(funct.ssh_command(serv, cmd))

View File

@ -0,0 +1,111 @@
{% from 'include/input_macros.html' import input, checkbox %}
<script>
$(document).ready(function() {
$('#{{list_id}}').on( 'page.dt', function () { $.getScript("/inc/fontawesome.min.js"); } )
.DataTable( {
"order": [[ 0, "desc" ]],
"pageLength": 25,
"columnDefs": [
{
"searchable": false,
"orderable": false,
"targets": 2
}
],
"lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
} );
} );
</script>
<table class="overview">
<tr class="overviewHead">
<td class="padding10 first-collumn" style="width: 95%">
List name: {{list_name}}
</td>
<td>
<button title="Add IP in this list" id="list_add_ip" data-list-id="{{list_id}}" data-list-name="{{list_name}}">Add IP</button>
</td>
</tr>
</table>
<table class="overview hover order-column display compact" id="{{list_id}}">
<thead>
<tr class="overviewHead">
<th class="padding10" style="width: 10%; padding-left: 10px;">
Id
</th>
<th>
Ip
</th>
<th>
</th>
</tr>
</thead>
<tbody>
{% for l in list %}
{% if l != '' %}
<tr>
<td class="padding10" style="width: 10%; padding-left: 10px;">
{{ loop.index }}
</td>
<td style="width: 85%">
{{l.split(' ')[1]}}
</td>
<td>
<a class="delete" title="Delete this IP" style="cursor: pointer;" onclick="deleteListIp(this, '{{list_id}}', '{{l.split(' ')[0]}}', '{{l.split(' ')[1]}}')"></a>
</td>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
<div id="list_add_ip_form" title="Add a new IP " style="display: none;">
<table class="overview">
<tr>
<td colspan="2">
<p class="validateTips alert alert-success">
Form fields tag "<span class="need-field">*</span>" are required.
</p>
</td>
</tr>
<tr>
<td class="padding20">
IP
<span class="need-field">*</span>
</td>
<td>
{{ input('list_add_ip_new_ip', size='30') }}
</td>
</tr>
</table>
</div>
<script>
$( function() {
$('#list_add_ip').click(function () {
addListIp.dialog('open');
});
var addListIp = $("#list_add_ip_form").dialog({
autoOpen: false,
resizable: false,
height: "auto",
width: 600,
modal: true,
title: "Add a new IP",
show: {
effect: "fade",
duration: 200
},
hide: {
effect: "fade",
duration: 200
},
buttons: {
"Add": function () {
addNewIp();
},
Cancel: function () {
$(this).dialog("destroy");
clearTips();
}
}
});
});
</script>

View File

@ -11,6 +11,7 @@
<li><a href="#maxconn">Change Maxconn</a></li>
<li><a href="#ip">Change IP and Port</a></li>
<li><a href="#table">Stick Table</a></li>
<li><a href="#lists">Lists</a></li>
{% endif %}
{% include 'include/login.html' %}
</ul>
@ -183,6 +184,38 @@
You can read how it works <a href="https://haproxy-wi.org/description.py?description=runtimeapi#ip" title="Change IP and Port" target="_blank">here</a>
</div>
</div>
<div id="lists">
<table class="overview">
<tr class="overviewHead">
<td class="padding10 first-collumn">Server</td>
<td>Choose List</td>
<td></td>
</tr>
<tr>
<td class="padding10 first-collumn" style="width: 25%;">
<form action="" method="post" id="runtimeapilist">
<select autofocus required name="list_serv_select" id="list_serv_select">
<option disabled selected>Choose server</option>
{% for select in selects %}
<option value="{{ select.2 }}">{{ select.1 }}</option>
{% endfor %}
</select>
</td>
<td>
<select required name="list_select" id="list_select">
</select>
</td>
<td>
<button type="submit" name="Enter" value="Enter" id="enter">Enter</button>
</td>
</form>
</tr>
</table>
<div id="ajaxlist"></div>
<div class="add-note addName alert-info" style="width: inherit; margin-right: 15px;">
You can read how it works <a href="https://haproxy-wi.org/description.py?description=runtimeapi#ip" title="Change IP and Port" target="_blank">here</a>
</div>
</div>
</div>
<script>
$( function() {

View File

@ -1135,7 +1135,6 @@ function change_select_acceleration(id) {
type: "POST",
success: function( data ) {
data = data.replace(/\s+/g,' ');
console.log('"'+data+'"');
if(parseFloat(data) < parseFloat('1.8') || data == ' ') {
$("#cache"+id).checkboxradio( "disable" );
} else {

View File

@ -34,8 +34,8 @@ $( function() {
type: "POST",
success: function( data ) {
data = data.replace(/\s+/g,' ');
if (data.indexOf('error:') != '-1') {
alert(data)
if (data.indexOf('error: ') != '-1') {
toastr.error(data);
} else {
var value = data.split('<br>')
$('#maxconnfront').find('option').remove();
@ -66,7 +66,7 @@ $( function() {
type: "POST",
success: function( data ) {
data = data.replace(/\s+/g,' ');
if (data.indexOf('error:') != '-1') {
if (data.indexOf('error: ') != '-1') {
toastr.error(data);
} else {
toastr.success(data);
@ -86,8 +86,8 @@ $( function() {
type: "POST",
success: function( data ) {
data = data.replace(/\s+/g,' ');
if (data.indexOf('error:') != '-1') {
alert(data)
if (data.indexOf('error: ') != '-1') {
toastr.error(data);
} else {
var value = data.split('<br>')
$('#ipbackend').find('option').remove();
@ -119,8 +119,8 @@ $( function() {
type: "POST",
success: function( data ) {
data = data.replace(/\s+/g,' ');
if (data.indexOf('error:') != '-1') {
alert(data)
if (data.indexOf('error: ') != '-1') {
toastr.error(data);
} else {
var value = data.split('<br>')
$('#backend_server').find('option').remove();
@ -154,8 +154,8 @@ $( function() {
type: "POST",
success: function( data ) {
data = data.replace(/\s+/g,' ');
if (data.indexOf('error:') != '-1') {
alert(data)
if (data.indexOf('error: ') != '-1') {
toastr.error(data);
} else {
var server = data.split(':')[0]
var port = data.split(':')[1]
@ -181,7 +181,7 @@ $( function() {
type: "POST",
success: function( data ) {
data = data.replace(/\s+/g,' ');
if (data.indexOf('error:') != '-1') {
if (data.indexOf('error: ') != '-1') {
toastr.error(data);
} else {
toastr.success(data);
@ -201,7 +201,7 @@ $( function() {
type: "POST",
success: function( data ) {
data = data.replace(/\s+/g,'');
if (data.indexOf('error:') != '-1') {
if (data.indexOf('error: ') != '-1') {
toastr.error(data);
} else {
var value = data.split(',')
@ -211,7 +211,7 @@ $( function() {
for(let i = 0; i < data.split(',').length; i++){
if(value[i] != '') {
value[i] = value[i].replace(/\s+/g,'');
$('#table_select').append($("<option titile='Show "+value[i]+" table'></option>")
$('#table_select').append($("<option title=\"Show table "+value[i]+"\"></option>")
.attr("value",value[i])
.text(value[i]));
}
@ -232,7 +232,7 @@ $( function() {
type: "POST",
success: function( data ) {
if (data.indexOf('error:') != '-1') {
$("#ajaxtable").html(data);
toastr.error(data);
} else {
$("#ajaxtable").html(data);
$( "input[type=submit], button" ).button();
@ -243,6 +243,51 @@ $( function() {
} );
return false;
});
$('#runtimeapilist').submit(function() {
getList();
return false;
});
$( "#list_serv_select" ).on('selectmenuchange',function() {
$.ajax( {
url: "options.py",
data: {
serv: $('#list_serv_select').val(),
list_serv_select: $('#list_serv_select').val(),
token: $('#token').val()
},
type: "POST",
success: function( data ) {
data = data.replace(/, /g, ',');
if (data.indexOf('error: ') != '-1') {
toastr.error(data);
} else {
var value = data.split(',');
$('#list_select').find('option').remove();
//$('#list_select').append($("<option titile='Show all tables'></option>").attr("value","All").text("All"));
for (let i = 0; i < data.split(',').length; i++) {
if (value[i] != '') {
value[i] = value[i].replace(/\'/g, '');
value[i] = value[i].replace('(', '');
value[i] = value[i].replace(')', '');
value[i] = value[i].replace('[', '');
value[i] = value[i].replace(']', '');
id = value[i].split(' ')[0];
full_text_option = value[i].split(' ')[1]
text_option = full_text_option.split('/').slice(-2)[0];
text_option = text_option + '/' + full_text_option.split('/').slice(-1)[0];
$('#list_select').append($("<option title=\"Show list " + text_option + "\"></option>")
.attr("value", id)
.text(text_option));
}
}
$('#list_select').selectmenu("refresh");
}
}
} );
});
});
function deleteTableEntry(id, table, ip) {
$(id).parent().parent().css("background-color", "#f2dede");
@ -256,11 +301,92 @@ function deleteTableEntry(id, table, ip) {
},
type: "POST",
success: function( data ) {
if (data.indexOf('error:') != '-1') {
if (data.indexOf('error: ') != '-1') {
toastr.error(data);
} else {
$(id).parent().parent().remove()
}
}
} );
}
function getList() {
$.ajax( {
url: "options.py",
data: {
serv: $('#list_serv_select').val(),
list_select_id: $('#list_select').val(),
list_select_name: $('#list_select option:selected').text(),
token: $('#token').val()
},
type: "POST",
success: function( data ) {
if (data.indexOf('error: ') != '-1') {
toastr.error(data);
} else {
$("#ajaxlist").html(data);
$( "input[type=submit], button" ).button();
$.getScript("/inc/fontawesome.min.js");
FontAwesomeConfig = { searchPseudoElements: true, observeMutations: false };
}
}
} );
}
function deleteListIp(id, list_id, ip_id, ip) {
toastr.clear();
$(id).parent().parent().css("background-color", "#f2dede !important");
$.ajax( {
url: "options.py",
data: {
serv: $('#list_serv_select').val(),
list_id_for_delete: list_id,
list_ip_id_for_delete: ip_id,
list_ip_for_delete: ip,
list_name: $('#list_add_ip').data("list-name"),
token: $('#token').val()
},
type: "POST",
success: function( data ) {
if (data.indexOf('error: ') != '-1') {
toastr.error(data);
} else {
$(id).parent().parent().remove();
toastr.info('Do not forget upload updated list to the properly server. Restart does not need');
getList();
}
}
} );
}
function addNewIp() {
toastr.clear();
var valid = true;
allFields = $( [] ).add( $('#list_add_ip_new_ip') );
allFields.removeClass( "ui-state-error" );
valid = valid && checkLength( $('#list_add_ip_new_ip'), "IP", 1 );
var ip = $('#list_add_ip_new_ip').val();
console.log($('#list_add_ip_new_ip').val());
console.log($('#list_add_ip').data("list-id"))
if(valid) {
$.ajax({
url: "options.py",
data: {
serv: $('#list_serv_select').val(),
list_ip_for_add: ip,
list_id_for_add: $('#list_add_ip').data("list-id"),
list_name: $('#list_add_ip').data("list-name"),
token: $('#token').val()
},
type: "POST",
success: function (data) {
if (data.indexOf('error: ') != '-1') {
toastr.error(data);
} else {
getList();
$( "#list_add_ip_form" ).dialog("destroy" );
toastr.success('IP ' + ip + ' has been added');
toastr.info('Do not forget upload updated list to the properly server. Restart does not need');
}
}
});
}
}

View File

@ -1061,6 +1061,7 @@ function showSmon(action) {
if (data.indexOf('SMON error:') != '-1') {
toastr.error(data);
} else {
toastr.clear();
$("#smon_dashboard").html(data);
if (action == 'not_sort') {
window.history.pushState("SMON Dashboard", document.title, "smon.py?action=view");
@ -1070,4 +1071,23 @@ function showSmon(action) {
}
}
} );
}
function updateTips( t ) {
var tips = $( ".validateTips" );
tips.text( t ).addClass( "alert-warning" );
}
function clearTips() {
var tips = $( ".validateTips" );
tips.html('Form fields tag "<span class="need-field">*</span>" are required.').removeClass( "alert-warning" );
allFields = $( [] ).add( $('#new-server-add') ).add( $('#new-ip') ).add( $('#new-port')).add( $('#new-username') ).add( $('#new-password') )
allFields.removeClass( "ui-state-error" );
}
function checkLength( o, n, min ) {
if ( o.val().length < min ) {
o.addClass( "ui-state-error" );
updateTips("Filed "+n+" is required");
return false;
} else {
return true;
}
}

View File

@ -77,7 +77,7 @@ pre {
margin-bottom: 0px;
}
.top-menu {
position: fixed;
position: absolute;
min-height: calc(99vh - 50px);
height: 120%;
width: 207px;
@ -631,7 +631,7 @@ ul{
.ui-selectmenu-open, .ui-selectmenu-menu {
z-index: 1010 !important;
}
.ui-widget.ui-widget-content {
#tabs.ui-widget.ui-widget-content {
border-bottom: none !important;
}
.need-field {

View File

@ -568,7 +568,7 @@ $( function() {
height: "auto",
width: 600,
modal: true,
title: "Add new user",
title: "Add a new user",
show: {
effect: "fade",
duration: 200
@ -593,7 +593,7 @@ $( function() {
height: "auto",
width: 600,
modal: true,
title: "Add new server",
title: "Add a new server",
show: {
effect: "fade",
duration: 200
@ -789,26 +789,6 @@ $( function() {
});
} );
function updateTips( t ) {
var tips = $( ".validateTips" );
tips.text( t ).addClass( "alert-warning" );
}
function clearTips() {
var tips = $( ".validateTips" );
tips.html('Form fields tag "<span class="need-field">*</span>" are required.').removeClass( "alert-warning" );
allFields = $( [] ).add( $('#new-server-add') ).add( $('#new-ip') ).add( $('#new-port')).add( $('#new-username') ).add( $('#new-password') )
allFields.removeClass( "ui-state-error" );
}
function checkLength( o, n, min ) {
if ( o.val().length < min ) {
o.addClass( "ui-state-error" );
updateTips("Filed "+n+" is required");
return false;
} else {
return true;
}
}
function addNewSmonServer() {
var valid = true;
allFields = $( [] ).add( $('#new-smon-ip') ).add( $('#new-smon-port') )