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 @@