From b6391fb8c58c08bfc946c5573f50e1931ee94d23 Mon Sep 17 00:00:00 2001 From: Pavel Loginov Date: Sun, 2 Feb 2020 17:23:00 +0300 Subject: [PATCH 1/3] v3.13.0.0 https://haproxy-wi.org/changelog.py#3_13 --- README.md | 22 +++---- app/config.py | 52 +++++++++++----- app/funct.py | 19 ++++-- app/hapservers.py | 1 + app/keepalivedconfig.py | 93 ----------------------------- app/options.py | 27 +++++++-- app/templates/ajax/config_show.html | 14 +++-- app/templates/ajax/overview.html | 13 +++- app/templates/base.html | 3 +- app/templates/config.html | 4 +- app/templates/configver.html | 3 +- app/templates/delver.html | 6 +- app/templates/hapservers.html | 31 +++++----- app/templates/ovw.html | 9 ++- app/versions.py | 67 +++++++++++++-------- inc/script.js | 63 ++++++++++++------- 16 files changed, 220 insertions(+), 207 deletions(-) delete mode 100644 app/keepalivedconfig.py diff --git a/README.md b/README.md index 66ed93e1..82527a14 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Haproxy web interface -Web interface(user-friendly web GUI, alerting, monitoring and secure) for managing Haproxy servers. Leave your [feedback](https://github.com/Aidaho12/haproxy-wi/issues) +Web interface(user-friendly web GUI, alerting, monitoring and secure) for managing HAProxy servers. Leave your [feedback](https://github.com/Aidaho12/haproxy-wi/issues) # Youtube [Demo video](https://www.youtube.com/channel/UCo0lCg24j-H4f0S9kMjp-_w) @@ -8,27 +8,27 @@ Web interface(user-friendly web GUI, alerting, monitoring and secure) for managi [Twitter](https://twitter.com/haproxy_wi), subscribe! I will write there about all the changes and news # Telegram -[Channel](https://t.me/haproxy_wi) about Haproxy-wi, talks and questions are welcome +[Channel](https://t.me/haproxy_wi) about HAProxy-WI, talks and questions are welcome # Demo site [Demo site](https://demo.haproxy-wi.org) Login/password: admin/admin. Server resets every hour. ![alt text](image/haproxy-wi-config-show.png "Show config page") # Features: -1. Configure HAProxy In a jiffy with HAProxy-WI +1. Configure HAProxy and Keepalived In a jiffy with HAProxy-WI 2. View and analyse Status of all Frontend/backend server via HAProxy-WI from a single control panel. 3. Enable/disable servers through stats page without rebooting HAProxy 4. View/Analyse HAproxy logs straight from the HAProxy-WI web interface -5. Create and visualise the HAproxy workflow from Web Ui. -6. Push Your changes to your HAproxy servers with a single click through web interface -7. Get info on past changes, Evaluate your config files and restore a previous stable config anytime with a single click straight from Web interface +5. Create and visualise the HAProxy workflow from Web Ui. +6. Push Your changes to your HAProxy and Keepalived servers with a single click through web interface +7. Get info on past changes, evaluate your config files and restore a previous stable config anytime with a single click straight from Web interface 8. Add/Edit Frontend or backend servers via web interface with a click of a button. -9. Edit config of HAProxy and push changes to All Master/Slave server with a single click +9. Edit config of HAProxy, Keepalived and push changes to All Master/Slave server with a single click 10. Add Multiple server to ensure Config Sync between servers. 11. Auto management of ports assigned to Fronted. -12. Evaluate the changes of recent configs pushed to HAproxy instances straight from web ui +12. Evaluate the changes of recent configs pushed to HAProxy and Keepalived instances straight from web ui 13. Multiple User Roles support for privileged based Viewing and editing of Config -14. Create Groups and add /remove servers to ensure proper identification for your HAproxy Clusters +14. Create Groups and add /remove servers to ensure proper identification for your HAProxy Clusters 15. Send notifications to telegram directly from HAProxy-WI 16. HAProxy-WI supports high Availability to ensure uptime to all Master slave servers configured 17. SSL certificate support. @@ -45,7 +45,7 @@ Web interface(user-friendly web GUI, alerting, monitoring and secure) for managi 28. Mobile-ready desing 29. REST API 30. Installation and Upgrading HAProxy service via HAProxy-WI -31. Backup HAProxy's config files through HAProxy-WI +31. Backup HAProxy's and Keepalived's config files through HAProxy-WI ![alt text](image/haproxy-wi-metrics.png "Merics") @@ -188,7 +188,7 @@ HAProxy-WI was tested on EL7, EL8 and all scripts too. Debian/Ubuntu OS support # Database support -Default Haproxy-WI use Sqlite, if you want use MySQL enable in config, and create database: +Default HAProxy-WI use Sqlite, if you want use MySQL enable in config, and create database: ### For MySQL support: ``` diff --git a/app/config.py b/app/config.py index 6fa04c5f..30d5f32e 100644 --- a/app/config.py +++ b/app/config.py @@ -13,6 +13,7 @@ funct.check_login() form = funct.form serv = form.getvalue('serv') +service = form.getvalue('service') config_read = "" cfg = "" stderr = "" @@ -23,25 +24,44 @@ 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 service == 'keepalived': + title = "Working with Keepalived configs" + action = "config.py?service=keepalived" + configs_dir = funct.get_config_var('configs', 'kp_save_configs_dir') + format = 'conf' + servers = sql.is_master("123", master_slave=1) + keepalived = 1 +else: + title = "Working with HAProxy configs" + action = "config.py" + configs_dir = funct.get_config_var('configs', 'haproxy_save_configs_dir') + format = 'cfg' + servers = sql.get_dick_permit() + keepalived = 0 if serv is not None: - cfg = hap_configs_dir + serv + "-" + funct.get_data('config') + ".cfg" + cfg = configs_dir + serv + "-" + funct.get_data('config') + "."+format if serv is not None and form.getvalue('open') is not None : - try: - funct.logging(serv, "config.py open config") - except: - pass - - error = funct.get_config(serv, cfg) + if service == 'keepalived': + error = funct.get_config(serv, cfg, keepalived=1) + try: + funct.logging(serv, "keepalivedconfig.py open config") + except: + pass + else: + error = funct.get_config(serv, cfg) + try: + funct.logging(serv, "config.py open config") + except: + pass try: conf = open(cfg, "r") @@ -67,17 +87,20 @@ if serv is not None and form.getvalue('config') is not None: conf.write(config) except IOError: error = "Can't read import config file" - - stderr = funct.master_slave_upload_and_restart(serv, cfg, just_save=save) + + if service == 'keepalived': + stderr = funct.upload_and_restart(serv, cfg, just_save=save, keepalived=1) + else: + stderr = funct.master_slave_upload_and_restart(serv, cfg, just_save=save) funct.diff_config(oldcfg, cfg) - os.system("/bin/rm -f " + hap_configs_dir + "*.old") + os.system("/bin/rm -f " + configs_dir + "*.old") -template = template.render(h2 = 1, title = "Working with HAProxy configs", +template = template.render(h2 = 1, title = title, role = role, - action = "config.py", + action = action, user = user, select_id = "serv", serv = serv, @@ -89,5 +112,6 @@ template = template.render(h2 = 1, title = "Working with HAProxy configs", error = error, note = 1, versions = funct.versions(), + keepalived = keepalived, token = token) print(template) diff --git a/app/funct.py b/app/funct.py index e95b9f49..8eaabee9 100644 --- a/app/funct.py +++ b/app/funct.py @@ -170,7 +170,7 @@ def return_ssh_keys_path(serv, **kwargs): ssh_user_name = '' ssh_user_password = '' - if kwargs.get('id') != '': + if kwargs.get('id'): for sshs in sql.select_ssh(id=kwargs.get('id')): ssh_enable = sshs[2] ssh_user_name = sshs[3] @@ -203,9 +203,9 @@ def ssh_connect(serv, **kwargs): try: if ssh_enable == 1: k = paramiko.RSAKey.from_private_key_file(ssh_key_name) - ssh.connect(hostname = serv, port = ssh_port, username = ssh_user_name, pkey = k) + ssh.connect(hostname = serv, port = ssh_port, username = ssh_user_name, pkey = k, timeout=11) else: - ssh.connect(hostname = serv, port = ssh_port, username = ssh_user_name, password = ssh_user_password) + ssh.connect(hostname = serv, port = ssh_port, username = ssh_user_name, password = ssh_user_password, timeout=11) return ssh except paramiko.AuthenticationException: return 'Authentication failed, please verify your credentials' @@ -235,7 +235,13 @@ def get_config(serv, cfg, **kwargs): ssh = ssh_connect(serv) try: sftp = ssh.open_sftp() + except Exception as e: + logging('localhost', ssh, haproxywi=1) + try: sftp.get(config_path, cfg) + except Exception as e: + logging('localhost', ssh, haproxywi=1) + try: sftp.close() ssh.close() except Exception as e: @@ -526,15 +532,16 @@ def upload_and_restart(serv, cfg, **kwargs): return error -def master_slave_upload_and_restart(serv, cfg, just_save): +def master_slave_upload_and_restart(serv, cfg, just_save, **kwargs): import sql MASTERS = sql.is_master(serv) error = "" for master in MASTERS: if master[0] != None: error += upload_and_restart(master[0], cfg, just_save=just_save) - + error += upload_and_restart(serv, cfg, just_save=just_save) + return error @@ -730,7 +737,7 @@ def get_files(dir = get_config_var('configs', 'haproxy_save_configs_dir'), forma file.add(files.split('/')[-1]) files = sorted(file, reverse=True) - if format == 'cfg': + if format == 'cfg' or format == 'conf': for file in files: ip = file.split("-") if serv == ip[0]: diff --git a/app/hapservers.py b/app/hapservers.py index 64364d3a..80310d4b 100644 --- a/app/hapservers.py +++ b/app/hapservers.py @@ -50,6 +50,7 @@ for s in servers: servers_with_status.append(out1) servers_with_status.append(s[12]) servers_with_status.append(sql.is_master(s[2])) + servers_with_status.append(sql.select_servers(server=s[2])) servers_with_status1.append(servers_with_status) diff --git a/app/keepalivedconfig.py b/app/keepalivedconfig.py deleted file mode 100644 index 2a08b2e6..00000000 --- a/app/keepalivedconfig.py +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/env python3 -import html -import cgi -import os -import http.cookies -import funct -import sql -from jinja2 import Environment, FileSystemLoader -env = Environment(loader=FileSystemLoader('templates/')) -template = env.get_template('config.html') - -print('Content-type: text/html\n') -funct.check_login() -funct.page_for_admin(level = 2) - -form = funct.form -serv = form.getvalue('serv') -log_path = funct.get_config_var('main', 'log_path') -kp_save_configs_dir = funct.get_config_var('configs', 'kp_save_configs_dir') -config_read = "" -cfg = "" -stderr = "" -aftersave = "" -error = "" - -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.is_master("123", master_slave=1) - token = sql.get_token(user_id.value) -except: - pass - - -if serv is not None: - cfg = kp_save_configs_dir+ serv + '-' + funct.get_data('config') + '.conf' - -if form.getvalue('serv') is not None and form.getvalue('open') is not None : - - try: - funct.logging(serv, "keepalivedconfig.py open config") - except: - pass - error = funct.get_config(serv, cfg, keepalived=1) - - try: - conf = open(cfg, "r",encoding='utf-8', errors='ignore') - config_read = conf.read() - conf.close - except IOError: - error += "
Can't read import config file" - - os.system("/bin/mv %s %s.old" % (cfg, cfg)) - -if form.getvalue('serv') is not None and form.getvalue('config') is not None: - try: - funct.logging(serv, "keepalivedconfig.py edited config") - except: - pass - - config = form.getvalue('config') - oldcfg = form.getvalue('oldconfig') - save = form.getvalue('save') - aftersave = 1 - try: - with open(cfg, "a") as conf: - conf.write(config) - except IOError: - error += "Can't read import config file" - - stderr = funct.upload_and_restart(serv, cfg, just_save=save, keepalived=1) - - funct.diff_config(oldcfg, cfg) - - os.system("/bin/rm -f " + kp_save_configs_dir + "*.old") - -output_from_parsed_template = template.render(h2 = 1, title = "Edit Runnig Keepalived config", - role = sql.get_user_role_by_uuid(user_id.value), - action = "keepalivedconfig.py", - user = user, - select_id = "serv", - serv = serv, - aftersave = aftersave, - config = config_read, - cfg = cfg, - selects = servers, - stderr = stderr, - error = error, - keepalived = 1, - versions = funct.versions(), - token = token) -print(output_from_parsed_template) diff --git a/app/options.py b/app/options.py index 1406b605..83ca0817 100644 --- a/app/options.py +++ b/app/options.py @@ -162,12 +162,20 @@ if act == "overview": server_status = () commands2 = [ "ps ax |grep waf/bin/modsecurity |grep -v grep |wc -l" ] cmd = 'echo "show info" |nc %s %s -w 1|grep -e "Process_num"' % (serv2, sql.get_setting('haproxy_sock_port')) + keepalived = sql.select_keealived(serv2) + if keepalived == 1: + command = [ "ps ax |grep keepalived|grep -v grep|wc -l" ] + keepalived_process = funct.ssh_command(serv2, command) + else: + keepalived_process = '' server_status = (serv1, serv2, funct.server_status(funct.subprocess_execute(cmd)), sql.select_servers(server=serv2, keep_alive=1), funct.ssh_command(serv2, commands2), - sql.select_waf_servers(serv2)) + sql.select_waf_servers(serv2), + sql.select_keealived(serv2), + keepalived_process) return server_status @@ -563,13 +571,16 @@ if serv is not None and form.getvalue('right') is not None: if serv is not None and act == "configShow": - hap_configs_dir = funct.get_config_var('configs', 'haproxy_save_configs_dir') + if form.getvalue('service') == 'keepalived': + configs_dir = funct.get_config_var('configs', 'kp_save_configs_dir') + else: + configs_dir = funct.get_config_var('configs', 'haproxy_save_configs_dir') if form.getvalue('configver') is None: - cfg = hap_configs_dir + serv + "-" + funct.get_data('config') + ".cfg" + cfg = configs_dir + serv + "-" + funct.get_data('config') + ".cfg" funct.get_config(serv, cfg) else: - cfg = hap_configs_dir + form.getvalue('configver') + cfg = configs_dir + form.getvalue('configver') try: conf = open(cfg, "r") @@ -580,7 +591,11 @@ if serv is not None and act == "configShow": env = Environment(loader=FileSystemLoader('templates/ajax'), autoescape=True, trim_blocks=True, lstrip_blocks=True, extensions=["jinja2.ext.loopcontrols", "jinja2.ext.do"]) template = env.get_template('config_show.html') - template = template.render(conf=conf, view=form.getvalue('view'), serv=serv, configver=form.getvalue('configver'), role=funct.is_admin(level=2)) + template = template.render(conf=conf, + serv=serv, + configver=form.getvalue('configver'), + role=funct.is_admin(level=2), + service=form.getvalue('service')) print(template) if form.getvalue('configver') is None: @@ -665,6 +680,8 @@ if form.getvalue('master'): os.system("rm -f %s" % script) sql.update_server_master(master, slave) + sql.update_keepalived(master) + sql.update_keepalived(slave) if form.getvalue('masteradd'): diff --git a/app/templates/ajax/config_show.html b/app/templates/ajax/config_show.html index 4f50ba1a..87748bdc 100644 --- a/app/templates/ajax/config_show.html +++ b/app/templates/ajax/config_show.html @@ -2,7 +2,9 @@

Config from {{serv}}

{% if role %} + {% if service != 'keepalived' %} Edit + {% endif %} {% endif %} Expand all @@ -27,9 +29,11 @@ {% if line.startswith('global') %} {{ line }} {% if role %} - - Edit - + {% if service != 'keepalived' %} + + Edit + + {% endif %} {% endif %}

{% continue %} @@ -171,13 +175,15 @@ {% if configver %}
-
+ + {% if service != 'keepalived' %} + {% endif %}
Note: If you reconfigure Master server, Slave will reconfigured automatically
diff --git a/app/templates/ajax/overview.html b/app/templates/ajax/overview.html index 969f4986..564dbbf2 100644 --- a/app/templates/ajax/overview.html +++ b/app/templates/ajax/overview.html @@ -11,11 +11,22 @@ {% endif %} + + {% if service.6|int() == 0 %} + + {% else %} + {% if service.7|int() >= 1 %} + + {% else %} + + {% endif %} + {% endif %} + {% if service.5.0|length() == 0 %} {% elif service.5.0 != '' and service.4|int() == 0 %} - + {% elif service.5.0 != '' and service.4|int() >= 1 %} {% endif %} diff --git a/app/templates/base.html b/app/templates/base.html index 404b94e9..fd94352d 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -83,7 +83,8 @@ Keepalived
  • diff --git a/app/templates/config.html b/app/templates/config.html index 388808e0..44910a3f 100644 --- a/app/templates/config.html +++ b/app/templates/config.html @@ -39,7 +39,8 @@ {% endif %} {% else %} {% if role <= 2 %} - + + Versions {% endif %} {% endif %} @@ -82,7 +83,6 @@
    Config is ok
    Go to view stats {% endif %} - {% endif %} + {% endif %} {% if aftersave != 1 %} diff --git a/app/templates/delver.html b/app/templates/delver.html index d4590ae0..17fb9fdb 100644 --- a/app/templates/delver.html +++ b/app/templates/delver.html @@ -10,19 +10,19 @@ {% if not aftersave and not open %}
    - Here you can work with previous versions of HAProxy configs. Roll back to them, view or delete + Here you can work with previous versions of {%if service == 'keepalived' %}Keepalived{%else%}HAProxy{%endif%} configs. Roll back to them, view or delete
    {% endif %}

    {% if open %}

    Choose old version

    -
    +
    {% for file in return_files %} - + Upload
    {% endfor %} diff --git a/app/templates/hapservers.html b/app/templates/hapservers.html index cf962b2b..a4420bb4 100644 --- a/app/templates/hapservers.html +++ b/app/templates/hapservers.html @@ -1,5 +1,6 @@ {% extends "base.html" %} {% block content %} +{% from 'include/input_macros.html' import input, checkbox, select %} {% if serv %}