Pavel Loginov 2021-10-17 11:57:51 +06:00
parent 6b955bf099
commit 36c843bfbe
22 changed files with 546 additions and 159 deletions

View File

@ -93,11 +93,11 @@ if serv is not None and form.getvalue('config') is not None:
print("error: Cannot read import config file")
if service == 'keepalived':
stderr = funct.upload_and_restart(serv, cfg, just_save=save, keepalived=1)
stderr = funct.upload_and_restart(serv, cfg, just_save=save, keepalived=1, oldcfg=oldcfg)
elif service == 'nginx':
stderr = funct.master_slave_upload_and_restart(serv, cfg, just_save=save, nginx=1)
stderr = funct.master_slave_upload_and_restart(serv, cfg, just_save=save, nginx=1, oldcfg=oldcfg)
else:
stderr = funct.master_slave_upload_and_restart(serv, cfg, just_save=save)
stderr = funct.master_slave_upload_and_restart(serv, cfg, just_save=save, oldcfg=oldcfg)
funct.diff_config(oldcfg, cfg)

View File

@ -806,7 +806,7 @@ def update_db_v_5_3_0(**kwargs):
def update_ver():
query = Version.update(version='5.3.0.0')
query = Version.update(version='5.3.1.0')
try:
query.execute()
except:

View File

@ -438,9 +438,23 @@ class ActionHistory(BaseModel):
primary_key = False
class ConfigVersion(BaseModel):
id = AutoField()
server_id = IntegerField()
user_id = IntegerField()
service = CharField()
local_path = CharField()
remote_path = CharField()
diff = TextField()
message = CharField(null=True)
date = DateTimeField(default=datetime.now)
class Meta:
table_name = 'config_versions'
def create_tables():
with conn:
conn.create_tables([User, Server, Role, Telegram, Slack, UUID, Token, ApiToken, Groups, UserGroups,
conn.create_tables([User, Server, Role, Telegram, Slack, UUID, Token, ApiToken, Groups, UserGroups, ConfigVersion,
Setting, Cred, Backup, Metrics, WafMetrics, Version, Option, SavedServer, Waf, ActionHistory,
PortScannerSettings, PortScannerPorts, PortScannerHistory, ProvidersCreds, ServiceSetting,
ProvisionedServers, MetricsHttpStatus, SMON, WafRules, Alerts, GeoipCodes, NginxMetrics])

View File

@ -294,6 +294,18 @@ def check_login(**kwargs):
return False
def get_user_id():
import sql
import http.cookies
cookie = http.cookies.SimpleCookie(os.environ.get("HTTP_COOKIE"))
user_uuid = cookie.get('uuid')
if user_uuid is not None:
user_id = sql.get_user_id_by_uuid(user_uuid.value)
return user_id
def is_admin(**kwargs):
import sql
import http.cookies
@ -425,7 +437,7 @@ def get_config(server_ip, cfg, **kwargs):
return
def diff_config(oldcfg, cfg):
def diff_config(oldcfg, cfg, **kwargs):
import http.cookies
import sql
cookie = http.cookies.SimpleCookie(os.environ.get("HTTP_COOKIE"))
@ -443,8 +455,14 @@ def diff_config(oldcfg, cfg):
output, stderr = subprocess_execute(cmd)
for line in output:
diff += date + " user: " + login + ", group: " + user_group + " " + line + "\n"
if kwargs.get('return_diff'):
for line in output:
diff += line + "\n"
return diff
else:
for line in output:
diff += date + " user: " + login + ", group: " + user_group + " " + line + "\n"
try:
log = open(log_path + "/config_edit-"+get_data('logs')+".log", "a")
log.write(diff)
@ -811,7 +829,6 @@ def check_haproxy_version(server_ip):
def upload(server_ip, path, file, **kwargs):
error = ""
full_path = path + file
if kwargs.get('dir') == "fullpath":
full_path = path
@ -854,6 +871,7 @@ def upload_and_restart(server_ip, cfg, **kwargs):
import sql
error = ''
container_name = ''
server_id = sql.select_server_id_by_ip(server_ip=server_ip)
if kwargs.get("nginx"):
service = 'nginx'
@ -892,7 +910,6 @@ def upload_and_restart(server_ip, cfg, **kwargs):
else:
commands = ["sudo mv -f " + tmp_file + " /etc/keepalived/keepalived.conf && sudo systemctl restart keepalived"]
elif service == "nginx":
server_id = sql.select_server_id_by_ip(server_ip=server_ip)
is_docker = sql.select_service_setting(server_id, 'nginx', 'dockerized')
if is_docker == '1':
container_name = sql.get_setting('nginx_container_name')
@ -917,7 +934,6 @@ def upload_and_restart(server_ip, cfg, **kwargs):
if sql.return_firewall(server_ip):
commands[0] += open_port_firewalld(cfg, server_ip=server_ip, service='nginx')
else:
server_id = sql.select_server_id_by_ip(server_ip=server_ip)
is_docker = sql.select_service_setting(server_id, 'haproxy', 'dockerized')
haproxy_service_name = "haproxy"
@ -958,6 +974,18 @@ def upload_and_restart(server_ip, cfg, **kwargs):
service=service)
except Exception as e:
logging('localhost', str(e), haproxywi=1)
# If master then save version of config in a new way
if not kwargs.get('slave'):
try:
diff = diff_config(kwargs.get('oldcfg'), cfg, return_diff=1)
except Exception as e:
logging('localhost', str(e), haproxywi=1)
try:
user_id = get_user_id()
sql.insert_config_version(server_id, user_id, service, cfg, config_path, diff)
except Exception as e:
logging('localhost', str(e), haproxywi=1)
except Exception as e:
logging('localhost', str(e), haproxywi=1)
return error
@ -983,9 +1011,9 @@ def master_slave_upload_and_restart(server_ip, cfg, just_save, **kwargs):
masters = sql.is_master(server_ip)
for master in masters:
if master[0] is not None:
error = upload_and_restart(master[0], cfg, just_save=just_save, nginx=kwargs.get('nginx'))
error = upload_and_restart(master[0], cfg, just_save=just_save, nginx=kwargs.get('nginx'), slave=1)
error = upload_and_restart(server_ip, cfg, just_save=just_save, nginx=kwargs.get('nginx'))
error = upload_and_restart(server_ip, cfg, just_save=just_save, nginx=kwargs.get('nginx'), oldcfg=kwargs.get('oldcfg'))
return error

58
app/history.py Normal file
View File

@ -0,0 +1,58 @@
#!/usr/bin/env python3
import funct
import sql
from jinja2 import Environment, FileSystemLoader
env = Environment(loader=FileSystemLoader('templates/'), autoescape=True)
template = env.get_template('history.html')
print('Content-type: text/html\n')
funct.check_login()
try:
user, user_id, role, token, servers, user_services = funct.get_users_params()
services = []
except:
pass
form = funct.form
serv = funct.is_ip_or_dns(form.getvalue('serv'))
service = form.getvalue('service')
if service == 'nginx':
if funct.check_login(service=2):
title = 'Nginx service history'
if serv:
if funct.check_is_server_in_group(serv):
server_id = sql.select_server_id_by_ip(serv)
history = sql.select_action_history_by_server_id_and_service(server_id, service)
elif service == 'keepalived':
if funct.check_login(service=3):
title = 'Keepalived service history'
if serv:
if funct.check_is_server_in_group(serv):
server_id = sql.select_server_id_by_ip(serv)
history = sql.select_action_history_by_server_id_and_service(server_id, service)
elif service == 'haproxy':
if funct.check_login(service=1):
title = "HAProxy service history"
if serv:
if funct.check_is_server_in_group(serv):
server_id = sql.select_server_id_by_ip(serv)
history = sql.select_action_history_by_server_id_and_service(server_id, service)
users = sql.select_users()
template = template.render(h2=1,
autorefresh=0,
title=title,
role=role,
user=user,
users=users,
serv=serv,
service=service,
history=history,
user_services=user_services,
token=token)
print(template)

View File

@ -393,7 +393,8 @@ if form.getvalue('session_delete_id') is not None:
if form.getvalue("change_pos") is not None:
pos = form.getvalue('change_pos')
sql.update_server_pos(pos, serv)
server_id = form.getvalue('pos_server_id')
sql.update_server_pos(pos, server_id)
if form.getvalue('show_ip') is not None and serv is not None:
commands = ["sudo ip a |grep inet |egrep -v '::1' |awk '{ print $2 }' |awk -F'/' '{ print $1 }'"]
@ -1397,7 +1398,7 @@ if form.getvalue('haproxy_exp_install'):
proxy_serv = ''
commands = ["chmod +x " + script + " && ./" + script + " PROXY=" + proxy_serv +
" STAT_PORT=" + stats_port + " STAT_FILE=" + server_state_file +
" STAT_PORT=" + str(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]
@ -1434,7 +1435,7 @@ if form.getvalue('nginx_exp_install'):
proxy_serv = ''
commands = ["chmod +x " + script + " && ./" + script + " PROXY=" + proxy_serv +
" STAT_PORT=" + stats_port + " SSH_PORT=" + ssh_port + " STAT_PAGE=" + stats_page +
" STAT_PORT=" + str(stats_port) + " SSH_PORT=" + ssh_port + " STAT_PAGE=" + stats_page +
" STATS_USER=" + stats_user + " STATS_PASS='" + stats_password + "' HOST=" + serv +
" USER=" + ssh_user_name + " PASS='" + ssh_user_password + "' KEY=" + ssh_key_name]
@ -3817,3 +3818,40 @@ if form.getvalue('serverSettingsSave') is not None:
else:
funct.logging(server_ip, 'Service has been flagged as a system service', haproxywi=1, login=1,
keep_history=1, service=service)
if act == 'showListOfVersion':
service = form.getvalue('service')
configver = form.getvalue('configver')
for_delver = form.getvalue('for_delver')
style = form.getvalue('style')
if service == 'keepalived':
configs_dir = funct.get_config_var('configs', 'kp_save_configs_dir')
files = funct.get_files(dir=configs_dir, format='conf')
configs = sql.select_config_version(serv, service)
action = 'versions.py?service=keepalived'
elif service == 'nginx':
configs_dir = funct.get_config_var('configs', 'nginx_save_configs_dir')
files = funct.get_files(dir=configs_dir, format='conf')
configs = sql.select_config_version(serv, service)
action = 'versions.py?service=nginx'
else:
service = 'haproxy'
files = funct.get_files()
configs = sql.select_config_version(serv, service)
action = "versions.py"
from jinja2 import Environment, FileSystemLoader
env = Environment(loader=FileSystemLoader('templates/'), autoescape=True,
extensions=["jinja2.ext.loopcontrols", "jinja2.ext.do"])
template = env.get_template('ajax/show_list_version.html')
template = template.render(serv=serv,
service=service,
action=action,
return_files=files,
configver=configver,
for_delver=for_delver,
configs=configs,
style=style)
print(template)

View File

@ -33,18 +33,6 @@
- sestatus.stdout is defined
- '"Enforcing" in sestatus.stdout'
- name: Get HAProxy version.
command: haproxy -v
register: haproxy_version_result
changed_when: false
check_mode: false
- name: Set HAProxy version.
set_fact:
haproxy_version: "{{ '1.5' if '1.5.' in haproxy_version_result.stdout else '1.6' }}"
- name: Open stat port for firewalld
firewalld:
port: "{{ item }}/tcp"
@ -70,16 +58,36 @@
ignore_errors: yes
with_items: [ "{{ STAT_PORT }}", "{{ SOCK_PORT }}" ]
- name: Create the haproxy group
group:
name: haproxy
state: present
system: true
- name: Create the haproxy user
user:
name: haproxy
groups: haproxy
append: true
shell: /usr/sbin/nologin
system: true
create_home: false
home: /
- name: Creates HAProxy directory
file:
path: /etc/haproxy
owner: haproxy
group: haproxy
state: directory
ignore_errors: yes
- name: Copy HAProxy configuration in place.
template:
src: haproxy.cfg.j2
dest: /etc/haproxy/haproxy.cfg
mode: 0644
validate: haproxy -f %s -c -q
force: no
notify: restart haproxy
- name: Creates HAProxy stats directory
file:
@ -88,13 +96,3 @@
group: haproxy
state: directory
ignore_errors: yes
- name: Enable and start service HAProxy
systemd:
name: haproxy
daemon_reload: yes
state: started
enabled: yes
force: no
ignore_errors: yes

View File

@ -12,10 +12,10 @@
- include: logs.yml
- include: installation.yml
- include: configure.yml
- include: installation.yml
- name: Add syn_flood tasks
include: syn_flood.yml
when: (SYN_FLOOD is defined) and (SYN_FLOOD|length > 0)

View File

@ -9,9 +9,7 @@ global
stats socket /var/lib/haproxy/stats
stats socket *:{{SOCK_PORT}} level admin
stats socket /var/run/haproxy.sock mode 600 level admin
{% if haproxy_version == '1.6' %}
server-state-file {{STAT_FILE}}
{% endif %}
defaults
mode http

View File

@ -1943,6 +1943,7 @@ def update_firewall(serv):
def update_server_pos(pos, server_id):
query = Server.update(pos=pos).where(Server.server_id == server_id)
print(query)
try:
query.execute()
return True
@ -1960,17 +1961,8 @@ def check_token_exists(token):
if get_token(user_id.value) == token:
return True
else:
# try:
# funct.logging('localhost', ' Tried do action with wrong token', haproxywi=1, login=1)
# except:
# funct.logging('localhost', ' An action with wrong token', haproxywi=1)
return False
except:
# try:
# funct.logging('localhost', ' Cannot check token', haproxywi=1, login=1)
# except:
# funct.logging('localhost', ' Cannot check token', haproxywi=1)
# finally:
return False
@ -1992,7 +1984,6 @@ def insert_smon(server, port, enable, proto, uri, body, group, desc, telegram, u
def select_smon(user_group, **kwargs):
cursor = conn.cursor()
funct.check_user_group()
if user_group == 1:
@ -2862,3 +2853,67 @@ def delete_action_history(server_id: int):
return False
else:
return True
def select_action_history_by_server_id(server_id: int):
query = ActionHistory.select().where(ActionHistory.server_id == server_id)
try:
query_res = query.execute()
except Exception as e:
out_error(e)
else:
return query_res
def select_action_history_by_server_id_and_service(server_id: int, service: str):
query = ActionHistory.select().where(
(ActionHistory.server_id == server_id) &
(ActionHistory.service == service)
)
try:
query_res = query.execute()
except Exception as e:
out_error(e)
else:
return query_res
def insert_config_version(server_id: int, user_id: int, service: str, local_path: str, remote_path: str, diff: str):
try:
ConfigVersion.insert(server_id=server_id,
user_id=user_id,
service=service,
local_path=local_path,
remote_path=remote_path,
diff=diff,
date=funct.get_data('regular')).execute()
except Exception as e:
out_error(e)
def select_config_version(server_ip: str, service: str) -> str:
server_id = select_server_id_by_ip(server_ip)
query = ConfigVersion.select().where(
(ConfigVersion.server_id == server_id) &
(ConfigVersion.service == service)
)
try:
query_res = query.execute()
except Exception as e:
out_error(e)
else:
return query_res
def delete_config_version(service: str, local_path: str):
query_res = ConfigVersion.delete().where(
(ConfigVersion.service == service) &
(ConfigVersion.local_path == local_path)
)
try:
query_res.execute()
except Exception as e:
out_error(e)
return False
else:
return True

View File

@ -0,0 +1,200 @@
{% from 'include/input_macros.html' import copy_to_clipboard %}
{% if style == 'new' %}
{% if for_delver == '1' %}
<script>
$(document).ready(function() {
$('#table_version').on('page.dt')
.DataTable( {
"pageLength": 25,
"order": [ 4, "desc" ],
stateSave: true,
"columnDefs": [
{
"searchable": false,
"orderable": false
}
],
"lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
} );
} );
$('#new_select_all').click(function(){
if($(this).prop('checked')) {
$("form input[type='checkbox']").attr("checked",true).change();
} else {
$("form input[type='checkbox']").attr("checked",false).change();
}
});
$.getScript('/inc/script.js');
function show_diff(id) {
if ($('#show_diff_'+id).css('display') == 'none') {
$('#show_diff_'+id).show();
$('#link_show_diff_'+id).attr('title', 'Hide the full diff');
$('#link_show_diff_'+id).text('Hide diff');
} else {
$('#show_diff_'+id).hide();
$('#link_show_diff_'+id).attr('title', 'Show the full diff');
$('#link_show_diff_'+id).text('Show diff');
}
}
</script>
<style>
.diff {
overflow: auto;
width: 100%;
border: 1px solid #DCDCDC;
border-radius: 5px;
background-color: #fff;
margin: 0;
}
</style>
<form action="{{action}}" method="post">
<table class="overview hover order-column display compact" id="table_version">
<thead>
<tr class="overviewHead">
<th class="padding10 first-collumn" style="width: 1%">
<label for="new_select_all" id="new_label_select_all"></label>
<input type="checkbox" id="new_select_all">
</th>
<th class="padding10 first-collumn" style="width: 30%">
Local path
</th>
<th class="padding10 first-collumn" style="width: 10%">
Remote path
</th>
<th class="padding10 first-collumn" style="width: 35%">
Diff
</th>
<th style="width: 10%">
Created
</th>
<th></th>
</tr>
</thead>
<tbody>
{% for c in configs %}
<tr>
<td>
<label for="{{c.id}}" id="select_{{c.id}}"></label>
<input type="checkbox" value="{{c.local_path}}" name="{{c.local_path}}" id="{{c.id}}">
</td>
<td class="padding10 first-collumn" title="{{c.local_path}}">
{% set show = '...'+c.local_path.split('/')[-1] %}
{{ copy_to_clipboard(id=c.local_path, value=c.local_path, show=show) }}
</td>
<td>{{ copy_to_clipboard(id=c.remote_path, value=c.remote_path) }}</td>
<td>
{% if c.diff == '' %}
No diff
{% else %}
<a id="link_show_diff_{{c.id}}" onclick="show_diff('{{c.id}}')" title="Show a difference between this config and previous one" class="link">Show diff</a>
<div id="show_diff_{{c.id}}" style="display: none;">
{% set stdout = c.diff.split('\n') %}
{% include 'ajax/compare.html' %}
</div>
{% endif %}
</td>
<td>{{c.date}}</td>
<td style="padding-top: 10px;">
<a href="/app/versions.py?service={{service}}&serv={{serv}}&open=open&configver={{c.local_path.split('/')[-1]}}"
class="ui-button ui-widget ui-corner-all" title="View and upload this version of the config" style="margin-top: -6px;">
View/Upload
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<input type="hidden" value="{{serv}}" name="serv">
<input type="hidden" value="open" name="open">
<input type="hidden" value="del" name="del">
<input type="hidden" value="{{style}}" name="style">
<input type="hidden" value="{{service}}" name="service">
<p>
<button type="submit" value="" name="" class="btn btn-default">Delete</button>
</p>
</form>
{% else %}
<center>
<h4>Select an old version</h4>
<p>
<select autofocus required name="configver" id="configver">
<option disabled selected>------</option>
{% for file in return_files %}
{% if file == configver %}
<option value="{{file}}" selected>{{file.split('-', maxsplit=1)[1]}}</option>
{% else %}
<option value="{{file}}">{{file.split('-', maxsplit=1)[1]}}</option>
{% endif %}
{% endfor %}
</select>
<input type="hidden" value="{{serv}}" name="serv">
<input type="hidden" value="open" name="open">
<input type="hidden" value="{{service}}" name="service" id="service">
<a class="ui-button ui-widget ui-corner-all" id="show" title="Enter" onclick="showUploadConfig()">Select</a>
</p>
<script>
$( "select" ).selectmenu();
showUploadConfig();
</script>
</center>
{% endif %}
{% else %}
{% if for_delver == '1' %}
<center>
<h4>Select a version</h4>
<form action="{{action}}" method="post">
<label for="select_all" id="label_select_all"><b>Select all</b></label>
<input type="checkbox" id="select_all"><br />
{% for file in return_files %}
<label for="{{file}}"> {{file.split('-', maxsplit=1)[1]}} </label><input type="checkbox" value="{{file}}" name="{{file}}" id="{{file}}">
<a href="/app/versions.py?service={{service}}&serv={{serv}}&open=open&configver={{file}}"
class="ui-button ui-widget ui-corner-all" title="View and upload this version of the config" style="margin-top: -6px;">
View/Upload
</a><br />
{% endfor %}
<input type="hidden" value="{{serv}}" name="serv">
<input type="hidden" value="open" name="open">
<input type="hidden" value="del" name="del">
<p>
<button type="submit" value="" name="" class="btn btn-default">Delete</button>
</p>
</form>
</center>
{% else %}
<center>
<h4>Select an old version</h4>
<p>
<select autofocus required name="configver" id="configver">
<option disabled selected>------</option>
{% for file in return_files %}
{% if file == configver %}
<option value="{{file}}" selected>{{file.split('-', maxsplit=1)[1]}}</option>
{% else %}
<option value="{{file}}">{{file.split('-', maxsplit=1)[1]}}</option>
{% endif %}
{% endfor %}
</select>
<input type="hidden" value="{{serv}}" name="serv">
<input type="hidden" value="open" name="open">
<input type="hidden" value="{{service}}" name="service" id="service">
<a class="ui-button ui-widget ui-corner-all" id="show" title="Enter" onclick="showUploadConfig()">Select</a>
</p>
<script>
$( "select" ).selectmenu();
showUploadConfig();
</script>
</center>
{% endif %}
{% endif %}
<script>
$('#select_all').click(function(){
if($(this).prop('checked')) {
$("form input[type='checkbox']").attr("checked",true).change();
$("#label_select_all").text("Unselect all");
} else {
$("form input[type='checkbox']").attr("checked",false).change();
$("#label_select_all").text("Select all");
}
});
$("input[type=submit], button").button();
</script>

View File

@ -14,25 +14,8 @@
{% endif %}
{% endif %}
{% if open %}
<center>
<h4>Choose old version</h4>
<p>
<select autofocus required name="configver" id="configver">
<option disabled selected>Choose version</option>
{% for file in return_files %}
{% if file == configver %}
<option value="{{file}}" selected>{{file.split('-', maxsplit=1)[1]}}</option>
{% else %}
<option value="{{file}}">{{file.split('-', maxsplit=1)[1]}}</option>
{% endif %}
{% endfor %}
</select>
<input type="hidden" value="{{serv}}" name="serv">
<input type="hidden" value="open" name="open">
<input type="hidden" value="{{service}}" name="service" id="service">
<a class="ui-button ui-widget ui-corner-all" id="show" title="Enter" onclick="showUploadConfig()">Select</a>
</p>
</center>
<div id="config_version_div"></div>
<script>showListOfVersion(0)</script>
{% endif %}
{% if aftersave %}
<div class="alert alert-info alert-two-row">The following version of the configuration file has been uploaded and saved as: {{ configver }} </div>
@ -44,9 +27,4 @@
{% endif %}
{% endif %}
</center>
{% if aftersave != 1 %}
<script>
showUploadConfig()
</script>
{% endif %}
{% endblock %}

View File

@ -4,21 +4,19 @@
{% if selects|length == 0 %}
{% include 'include/getstarted.html' %}
{% else %}
<link href="/inc/table.css" rel="stylesheet" type="text/css">
<script type="text/javascript" charset="utf8" src="/inc/dataTables.min.js"></script>
<center>
<p>
<form action="{{ action }}" method="post">
<input type="hidden" value="{{service}}" name="service" id="service">
{% include 'include/select.html' %}
<button type="submit" value="open" name="open" class="btn btn-default">Open</button>
<a class="ui-button ui-widget ui-corner-all" title="View stat" onclick="showListOfVersion(1)">Open</a>
{% if service != 'keepalived' %}
<a href="config.py" class="ui-button ui-widget ui-corner-all" title="Configs page">Configs</a>
<a class="ui-button ui-widget ui-corner-all" title="View stat" onclick="openStats()">Stat</a>
{% endif %}
</form>
{% if not aftersave and not open %}
<div class="add-note addName alert-info" style="width: inherit; margin-right: 15px; margin-top: 40%">
Here you can work with previous versions of {%if service == 'keepalived' %}Keepalived{%elif service == 'nginx' %}Nginx{%else%}HAProxy{%endif%} configs. Roll back to them, view or delete
</div>
{% endif %}
</p>
{% if aftersave %}
<div class="alert alert-info"><b>The following files have been deleted:</b><br /> </div>
@ -32,26 +30,11 @@
</div>
{% endif %}
{% endif %}
{% if open %}
<center>
<h4>Select a version</h4>
<form action="{{action}}" method="post">
<label for="select_all" id="label_select_all"><b>Select all</b></label>
<input type="checkbox" id="select_all"><br />
{% for file in return_files %}
<label for="{{file}}"> {{file.split('-', maxsplit=1)[1]}} </label><input type="checkbox" value="{{file}}" name="{{file}}" id="{{file}}">
<a href="/app/versions.py?service={{service}}&serv={{serv}}&open=open&configver={{file}}" class="ui-button ui-widget ui-corner-all" title="View and upload this version of the config" style="margin-top: -6px;">
View/Upload
</a><br />
{% endfor %}
<input type="hidden" value="{{serv}}" name="serv">
<input type="hidden" value="open" name="open">
<input type="hidden" value="del" name="del">
<p>
<button type="submit" value="" name="" class="btn btn-default">Delete</button>
</p>
</form>
</center>
<div id="config_version_div"></div>
{% if not aftersave %}
<div class="add-note addName alert-info" style="width: inherit; margin-right: 15px; margin-top: 40%">
Here you can work with previous versions of {%if service == 'keepalived' %}Keepalived{%elif service == 'nginx' %}Nginx{%else%}HAProxy{%endif%} configs. Roll back to them, view or delete
</div>
{% endif %}
</center>
{% endif %}

View File

@ -123,19 +123,6 @@
<div class="server-name">
<input type="hidden" id="server-name-{{s.0}}" value="{{s.1}}" />
<input type="hidden" id="service" value="{{service}}" />
{% if service == 'nginx' or service == 'keepalived' %}
{% if s.5.0.1 == 'active' %}
<span class="serverUp server-status" title="Started: {{s.5.0.4}}"></span>
{% else %}
<span class="serverDown server-status" title="Stopped: {{s.5.0.4}}"></span>
{% endif %}
{% else %}
{% if s.5 != False %}
<span class="serverUp server-status" title="{{s.5.0.2}}"></span>
{% else %}
<span class="serverDown server-status" title="HAProxy is down"></span>
{% endif %}
{% endif %}
{% if not serv %}
<a href="/app/hapservers.py?service={{service}}&serv={{s.2}}" title="More about {{s.1}}" style="color: #5d9ceb">{{s.1}}</a>
{% else %}
@ -172,8 +159,9 @@
<a id="stop-{{ s.2 }}" class="stop" title="Stop {{service}} service">
<span class="service-stop" onclick="confirmAjaxAction('stop', '{{action_service}}', '{{s.2}}')"></span>
</a>
<a href="history.py?service={{service}}&serv={{s.2}}" title="View history for this service" class="history" style="margin: 0 5px 0 10px;"></a>
{% if service != 'keepalived' %}
<span class="menu-bar" onclick="serverSettings('{{s.0}}', '{{s.1}}')" title="Edit settings for {{s.1}} service" style="margin: 0 0 0 10px;"></span>
<span class="menu-bar" onclick="serverSettings('{{s.0}}', '{{s.1}}')" title="Edit settings for {{s.1}} service"></span>
{% endif %}
</span>
{% endif %}

View File

@ -0,0 +1,51 @@
{% from 'include/input_macros.html' import copy_to_clipboard %}
{% extends "base.html" %}
{% block content %}
<link href="/inc/table.css" rel="stylesheet" type="text/css">
<script type="text/javascript" charset="utf8" src="/inc/dataTables.min.js"></script>
<script>
$(document).ready(function() {
$('#table_history').on('page.dt')
.DataTable( {
"pageLength": 25,
"order": [ 4, "desc" ],
stateSave: true,
"columnDefs": [
{
"searchable": false,
"orderable": false
}
],
"lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
} );
} );
</script>
<table class="overview hover order-column display compact" id="table_history">
<thead>
<tr class="overviewHead">
<th class="padding10 first-collumn" style="width: 100px;">Service</th>
<th>User</th>
<th>User IP</th>
<th>Action</th>
<th>Date</th>
</tr>
</thead>
<tbody>
{% for h in history %}
<tr>
<td>{{h.service[0].upper()}}{{h.service[1:]}}</td>
<td>
{% for u in users %}
{% if u.user_id == h.user_id %}
{{ u.username }}
{% endif %}
{% endfor %}
</td>
<td>{{ copy_to_clipboard(id=h.ip, value=h.ip) }}</td>
<td>{{h.action}}</td>
<td>{{h.date}}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

View File

@ -14,43 +14,40 @@ serv = form.getvalue('serv')
Select = form.getvalue('del')
configver = form.getvalue('configver')
service = form.getvalue('service')
conf_format = 'cfg'
configs_dir = ''
stderr = ""
aftersave = ""
file = set()
if form.getvalue('configver'):
if configver:
template = env.get_template('configver.html')
try:
user, user_id, role, token, servers, user_services = funct.get_users_params(disable=1)
except:
pass
if service == 'keepalived':
if funct.check_login(service=3):
configs_dir = funct.get_config_var('configs', 'kp_save_configs_dir')
title = "Working with versions Keepalived configs"
files = funct.get_files(dir=configs_dir, format='conf')
action = 'versions.py?service=keepalived'
format = 'conf'
conf_format = 'conf'
servers = sql.get_dick_permit(keepalived=1)
action = 'versions.py?service=keepalived'
elif service == 'nginx':
if funct.check_login(service=2):
configs_dir = funct.get_config_var('configs', 'nginx_save_configs_dir')
title = "Working with versions Nginx configs"
files = funct.get_files(dir=configs_dir, format='conf')
action = 'versions.py?service=nginx'
format = 'conf'
conf_format = 'conf'
servers = sql.get_dick_permit(nginx=1)
action = 'versions.py?service=nginx'
else:
service = 'haproxy'
if funct.check_login(service=1):
title = "Working with versions HAProxy configs"
files = funct.get_files()
action = "versions.py"
configs_dir = funct.get_config_var('configs', 'haproxy_save_configs_dir')
format = 'cfg'
action = "versions.py"
if serv is not None and form.getvalue('del') is not None:
if Select is not None:
@ -58,15 +55,21 @@ if serv is not None and form.getvalue('del') is not None:
env = Environment(loader=FileSystemLoader('templates/'))
template = env.get_template('delver.html')
for get in form:
if format in get:
if conf_format in get:
try:
os.remove(os.path.join(configs_dir, form.getvalue(get)))
if form.getvalue('style') == 'new':
if sql.delete_config_version(form.getvalue('service'), form.getvalue(get)):
try:
os.remove(form.getvalue(get))
except OSError as e:
if 'No such file or directory' in str(e):
pass
else:
os.remove(os.path.join(configs_dir, form.getvalue(get)))
file.add(form.getvalue(get) + "<br />")
funct.logging(serv, "versions.py were deleted configs: %s" % form.getvalue(get))
except OSError as e:
funct.logging(serv, "versions.py were deleted configs: %s" % form.getvalue(get))
except OSError as e:
stderr = "Error: %s - %s." % (e.filename,e.strerror)
print('<meta http-equiv="refresh" content="10; url=versions.py?service=%s&serv=%s&open=open">' % (service, form.getvalue('serv')))
if serv is not None and form.getvalue('config') is not None:
configver = configs_dir + configver
@ -88,19 +91,18 @@ if serv is not None and form.getvalue('config') is not None:
template = template.render(h2=1, title=title,
role=role,
action=action,
user=user,
select_id="serv",
serv=serv,
aftersave=aftersave,
return_files=files,
selects=servers,
stderr=stderr,
open=form.getvalue('open'),
Select=form.getvalue('del'),
file=file,
file=file,
configver=configver,
service=service,
user_services=user_services,
action=action,
token=token)
print(template)

View File

@ -396,3 +396,12 @@
margin-left: 5px;
content: "\f0c5";
}
.history::before {
display: none;
font-family: "Font Awesome 5 Solid";
content: "\f1da";
}
.history .fa-history {
margin-bottom: 3px;
color: #aaa;
}

View File

@ -61,7 +61,7 @@ $( function() {
type: frm.attr('method'),
success: function( data ) {
data = data.replace('\n', '<br>');
if (data.indexOf('error: ') != '-1' || data.indexOf('Fatal') != '-1' || data.indexOf('Error(s)') != '-1' || data.indexOf('failed ') != '-1' || data.indexOf('emerg] ') != '-1') {
if (data.indexOf('error: ') != '-1' || data.indexOf('Fatal') != '-1' || data.indexOf('Error') != '-1' || data.indexOf('failed ') != '-1' || data.indexOf('emerg] ') != '-1') {
toastr.clear();
toastr.error(data);
} else {

View File

@ -119,7 +119,7 @@ function add_master_addr(kp) {
type: "POST",
success: function( data ) {
data = data.replace(/\s+/g,' ');
if (data.indexOf('error:') != '-1' || data.indexOf('UNREACHABLE') != '-1') {
if (data.indexOf('error:') != '-1' || data.indexOf('UNREACHABLE') != '-1' || data.indexOf('FAILED') != '-1') {
showProvisioningError(data, '#creating-master-add', '#wait-mess-add', '#creating-error-add');
} else if (data == '' ){
showProvisioningWarning('#creating-master-add', 'master Keepalived', '#creating-warning-add', '#wait_mess-add');
@ -143,7 +143,7 @@ function add_slave_addr(kp) {
type: "POST",
success: function( data ) {
data = data.replace(/\s+/g,' ');
if (data.indexOf('error:') != '-1' || data.indexOf('UNREACHABLE') != '-1') {
if (data.indexOf('error:') != '-1' || data.indexOf('UNREACHABLE') != '-1' || data.indexOf('FAILED') != '-1') {
showProvisioningError(data, '#creating-slave-add', '#wait-mess-add', '#creating-error-add');
} else if (data == '' ){
showProvisioningWarning('#creating-slave-add', 'master Keepalived', '#creating-warning-add', '#wait_mess-add');

View File

@ -320,7 +320,7 @@ function renderNginxChart(data, labels, server) {
maintainAspectRatio: false,
title: {
display: true,
text: "Nginx "+data[1],
text: data[1],
fontSize: 20,
padding: 0,
},

View File

@ -389,7 +389,7 @@ function change_pos(pos, id) {
url: "options.py",
data: {
change_pos: pos,
serv: id,
pos_server_id: id,
token: $('#token').val()
},
error: function(){

View File

@ -1,18 +1,5 @@
var awesome = "/inc/fontawesome.min.js"
jQuery.expr[':'].regex = function(elem, index, match) {
var matchParams = match[3].split(','),
validLabels = /^(data|css):/,
attr = {
method: matchParams[0].match(validLabels) ?
matchParams[0].split(':')[0] : 'attr',
property: matchParams.shift().replace(validLabels,'')
},
regexFlags = 'ig',
regex = new RegExp(matchParams.join('').replace(/^\s+|\s+$/g,''), regexFlags);
return regex.test(jQuery(elem)[attr.method](attr.property));
}
$( function() {
$( "#interface" ).autocomplete({
source: function( request, response ) {