mirror of https://github.com/Aidaho12/haproxy-wi
parent
9146deac83
commit
072daa52d1
|
@ -632,6 +632,36 @@ def update_db_v_4_4_2_1(**kwargs):
|
||||||
con.close()
|
con.close()
|
||||||
|
|
||||||
|
|
||||||
|
def update_db_v_4_3_2_1(**kwargs):
|
||||||
|
con, cur = get_cur()
|
||||||
|
groups = ''
|
||||||
|
sql = """ select id from `groups` """
|
||||||
|
try:
|
||||||
|
cur.execute(sql)
|
||||||
|
except sqltool.Error as e:
|
||||||
|
funct.out_error(e)
|
||||||
|
else:
|
||||||
|
groups = cur.fetchall()
|
||||||
|
|
||||||
|
for g in groups:
|
||||||
|
sql = """
|
||||||
|
INSERT INTO settings (param, value, section, `desc`, `group`) values('haproxy_enterprise', '0', 'haproxy', 'Use this option, if your HAProxy is enterprise. It change service name for rebooting/reloading', '%s');
|
||||||
|
""" % g[0]
|
||||||
|
try:
|
||||||
|
cur.execute(sql)
|
||||||
|
con.commit()
|
||||||
|
except sqltool.Error as e:
|
||||||
|
if kwargs.get('silent') != 1:
|
||||||
|
if e.args[0] == 'columns param, group are not unique' or e == " 1060 (42S21): columns param, group are not unique ":
|
||||||
|
print('Updating... groups')
|
||||||
|
else:
|
||||||
|
print("An error occurred:", e)
|
||||||
|
else:
|
||||||
|
print("Updating... groups")
|
||||||
|
cur.close()
|
||||||
|
con.close()
|
||||||
|
|
||||||
|
|
||||||
def update_db_v_4_5(**kwargs):
|
def update_db_v_4_5(**kwargs):
|
||||||
con, cur = get_cur()
|
con, cur = get_cur()
|
||||||
sql = """CREATE TABLE IF NOT EXISTS `alerts` (`id` INTEGER NOT NULL,
|
sql = """CREATE TABLE IF NOT EXISTS `alerts` (`id` INTEGER NOT NULL,
|
||||||
|
@ -661,7 +691,7 @@ def update_db_v_4_5(**kwargs):
|
||||||
|
|
||||||
def update_ver(**kwargs):
|
def update_ver(**kwargs):
|
||||||
con, cur = get_cur()
|
con, cur = get_cur()
|
||||||
sql = """update version set version = '4.4.3.0'; """
|
sql = """update version set version = '4.5.0.0'; """
|
||||||
try:
|
try:
|
||||||
cur.execute(sql)
|
cur.execute(sql)
|
||||||
con.commit()
|
con.commit()
|
||||||
|
@ -693,6 +723,7 @@ def update_all():
|
||||||
update_db_v_4_4()
|
update_db_v_4_4()
|
||||||
update_db_v_4_4_2()
|
update_db_v_4_4_2()
|
||||||
update_db_v_4_4_2_1()
|
update_db_v_4_4_2_1()
|
||||||
|
update_db_v_4_3_2_1()
|
||||||
update_db_v_4_5()
|
update_db_v_4_5()
|
||||||
update_ver()
|
update_ver()
|
||||||
|
|
||||||
|
@ -719,6 +750,7 @@ def update_all_silent():
|
||||||
update_db_v_4_4(silent=1)
|
update_db_v_4_4(silent=1)
|
||||||
update_db_v_4_4_2(silent=1)
|
update_db_v_4_4_2(silent=1)
|
||||||
update_db_v_4_4_2_1(silent=1)
|
update_db_v_4_4_2_1(silent=1)
|
||||||
|
update_db_v_4_3_2_1(silent=1)
|
||||||
update_db_v_4_5(silent=1)
|
update_db_v_4_5(silent=1)
|
||||||
update_ver()
|
update_ver()
|
||||||
|
|
||||||
|
|
25
app/funct.py
25
app/funct.py
|
@ -708,14 +708,21 @@ def upload_and_restart(serv, cfg, **kwargs):
|
||||||
if sql.get_setting('firewall_enable') == "1":
|
if sql.get_setting('firewall_enable') == "1":
|
||||||
commands[0] += open_port_firewalld(cfg, serv=serv, service='nginx')
|
commands[0] += open_port_firewalld(cfg, serv=serv, service='nginx')
|
||||||
else:
|
else:
|
||||||
if kwargs.get("just_save") == "test":
|
haproxy_enterprise = sql.get_setting('haproxy_enterprise')
|
||||||
commands = [ "sudo haproxy -q -c -f " + tmp_file + " && sudo rm -f " + tmp_file ]
|
|
||||||
elif kwargs.get("just_save") == "save":
|
if haproxy_enterprise:
|
||||||
commands = [ "sudo haproxy -q -c -f " + tmp_file + " && sudo mv -f " + tmp_file + " " + config_path ]
|
haproxy_service_name = "hapee-2.0-lb"
|
||||||
elif kwargs.get("just_save") == "reload":
|
|
||||||
commands = [ "sudo haproxy -q -c -f " + tmp_file + " && sudo mv -f " + tmp_file + " " + config_path + " && sudo systemctl reload haproxy" ]
|
|
||||||
else:
|
else:
|
||||||
commands = [ "sudo haproxy -q -c -f " + tmp_file + " && sudo mv -f " + tmp_file + " " + config_path + " && sudo systemctl restart haproxy" ]
|
haproxy_service_name = "haproxy"
|
||||||
|
|
||||||
|
if kwargs.get("just_save") == "test":
|
||||||
|
commands = [ "sudo "+haproxy_service_name+" -q -c -f " + tmp_file + " && sudo rm -f " + tmp_file ]
|
||||||
|
elif kwargs.get("just_save") == "save":
|
||||||
|
commands = [ "sudo "+haproxy_service_name+" -q -c -f " + tmp_file + " && sudo mv -f " + tmp_file + " " + config_path ]
|
||||||
|
elif kwargs.get("just_save") == "reload":
|
||||||
|
commands = [ "sudo "+haproxy_service_name+" -q -c -f " + tmp_file + " && sudo mv -f " + tmp_file + " " + config_path + " && sudo systemctl reload "+haproxy_service_name+"" ]
|
||||||
|
else:
|
||||||
|
commands = [ "sudo "+haproxy_service_name+" -q -c -f " + tmp_file + " && sudo mv -f " + tmp_file + " " + config_path + " && sudo systemctl restart "+haproxy_service_name+"" ]
|
||||||
if sql.get_setting('firewall_enable') == "1":
|
if sql.get_setting('firewall_enable') == "1":
|
||||||
commands[0] += open_port_firewalld(cfg, serv=serv)
|
commands[0] += open_port_firewalld(cfg, serv=serv)
|
||||||
error += str(upload(serv, tmp_file, cfg, dir='fullpath'))
|
error += str(upload(serv, tmp_file, cfg, dir='fullpath'))
|
||||||
|
@ -894,9 +901,9 @@ def show_haproxy_log(serv, rows=10, waf='0', grep=None, hour='00', minut='00', h
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
if serv == 'backup.log':
|
if serv == 'backup.log':
|
||||||
cmd="cat %s| awk '$2>\"%s:00\" && $2<\"%s:00\"' |tail -%s %s %s %s" % (log_path + serv, date, date1, rows, user_grep, grep_act, exgrep_act)
|
cmd="cat %s| awk '$2>\"%s:00\" && $2<\"%s:00\"' %s %s %s |tail -%s" % (log_path + serv, date, date1, user_grep, grep_act, exgrep_act, rows)
|
||||||
else:
|
else:
|
||||||
cmd="cat %s| awk '$3>\"%s:00\" && $3<\"%s:00\"' |tail -%s %s %s %s" % (log_path + serv, date, date1, rows, user_grep, grep_act, exgrep_act)
|
cmd="cat %s| awk '$3>\"%s:00\" && $3<\"%s:00\"' %s %s %s |tail -%s" % (log_path + serv, date, date1, user_grep, grep_act, exgrep_act, rows)
|
||||||
|
|
||||||
output, stderr = subprocess_execute(cmd)
|
output, stderr = subprocess_execute(cmd)
|
||||||
|
|
||||||
|
|
114
app/options.py
114
app/options.py
|
@ -333,6 +333,50 @@ if form.getvalue('list_ip_for_add') is not None:
|
||||||
print('error: ' + stderr[0])
|
print('error: ' + stderr[0])
|
||||||
|
|
||||||
|
|
||||||
|
if form.getvalue('sessions_select') is not None:
|
||||||
|
from jinja2 import Environment, FileSystemLoader
|
||||||
|
env = Environment(loader=FileSystemLoader('templates/ajax'), autoescape=True,extensions=['jinja2.ext.loopcontrols', 'jinja2.ext.do'], trim_blocks=True, lstrip_blocks=True)
|
||||||
|
serv = form.getvalue('sessions_select')
|
||||||
|
haproxy_sock_port = sql.get_setting('haproxy_sock_port')
|
||||||
|
|
||||||
|
cmd = 'echo "show sess" |nc %s %s' % (serv, haproxy_sock_port)
|
||||||
|
output, stderr = funct.subprocess_execute(cmd)
|
||||||
|
|
||||||
|
template = env.get_template('/sessions_table.html')
|
||||||
|
template = template.render(sessions=output)
|
||||||
|
|
||||||
|
print(template)
|
||||||
|
|
||||||
|
|
||||||
|
if form.getvalue('sessions_select_show') is not None:
|
||||||
|
serv = form.getvalue('sessions_select_show')
|
||||||
|
sess_id = form.getvalue('sessions_select_id')
|
||||||
|
haproxy_sock_port = sql.get_setting('haproxy_sock_port')
|
||||||
|
|
||||||
|
cmd = 'echo "show sess %s" |nc %s %s' % (sess_id, serv, haproxy_sock_port)
|
||||||
|
output, stderr = funct.subprocess_execute(cmd)
|
||||||
|
|
||||||
|
output, stderr = funct.subprocess_execute(cmd)
|
||||||
|
|
||||||
|
if stderr:
|
||||||
|
print('error: ' + stderr[0])
|
||||||
|
else:
|
||||||
|
for o in output:
|
||||||
|
print(o+'<br />')
|
||||||
|
|
||||||
|
|
||||||
|
if form.getvalue('session_delete_id') is not None:
|
||||||
|
haproxy_sock_port = sql.get_setting('haproxy_sock_port')
|
||||||
|
sess_id = form.getvalue('session_delete_id')
|
||||||
|
|
||||||
|
cmd='echo "shutdown session %s" |nc %s %s' % (sess_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("change_pos") is not None:
|
if form.getvalue("change_pos") is not None:
|
||||||
pos = form.getvalue('change_pos')
|
pos = form.getvalue('change_pos')
|
||||||
sql.update_server_pos(pos, serv)
|
sql.update_server_pos(pos, serv)
|
||||||
|
@ -352,10 +396,16 @@ if form.getvalue('action_hap') is not None and serv is not None:
|
||||||
action = form.getvalue('action_hap')
|
action = form.getvalue('action_hap')
|
||||||
|
|
||||||
if funct.check_haproxy_config(serv):
|
if funct.check_haproxy_config(serv):
|
||||||
commands = [ "sudo systemctl %s haproxy" % action ]
|
haproxy_enterprise = sql.get_setting('haproxy_enterprise')
|
||||||
|
if haproxy_enterprise:
|
||||||
|
haproxy_service_name = "hapee-2.0-lb"
|
||||||
|
else:
|
||||||
|
haproxy_service_name = "haproxy"
|
||||||
|
|
||||||
|
commands = ["sudo systemctl %s %s" % (action, haproxy_service_name)]
|
||||||
funct.ssh_command(serv, commands)
|
funct.ssh_command(serv, commands)
|
||||||
funct.logging(serv, 'HAProxy was '+action+'ed', haproxywi=1, login=1)
|
funct.logging(serv, 'HAProxy was '+action+'ed', haproxywi=1, login=1)
|
||||||
print("success: HAproxy was %s" % action)
|
print("success: HAProxy was %s" % action)
|
||||||
else:
|
else:
|
||||||
print("error: Bad config, check please")
|
print("error: Bad config, check please")
|
||||||
|
|
||||||
|
@ -1492,10 +1542,17 @@ if form.getvalue('bwlists_save'):
|
||||||
funct.logging(serv, 'has edited '+color+' list '+bwlists_save, haproxywi=1, login=1)
|
funct.logging(serv, 'has edited '+color+' list '+bwlists_save, haproxywi=1, login=1)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
haproxy_enterprise = sql.get_setting('haproxy_enterprise')
|
||||||
|
if haproxy_enterprise:
|
||||||
|
haproxy_service_name = "hapee-2.0-lb"
|
||||||
|
else:
|
||||||
|
haproxy_service_name = "haproxy"
|
||||||
|
|
||||||
if form.getvalue('bwlists_restart') == 'restart':
|
if form.getvalue('bwlists_restart') == 'restart':
|
||||||
funct.ssh_command(serv, ["sudo systemctl restart haproxy"])
|
funct.ssh_command(serv, ["sudo systemctl restart "+haproxy_service_name])
|
||||||
elif form.getvalue('bwlists_restart') == 'reload':
|
elif form.getvalue('bwlists_restart') == 'reload':
|
||||||
funct.ssh_command(serv, ["sudo systemctl reload haproxy"])
|
funct.ssh_command(serv, ["sudo systemctl reload "+haproxy_service_name])
|
||||||
|
|
||||||
|
|
||||||
if form.getvalue('get_lists'):
|
if form.getvalue('get_lists'):
|
||||||
|
@ -2071,3 +2128,52 @@ if form.getvalue('waf_rule_id'):
|
||||||
|
|
||||||
print(funct.ssh_command(serv, cmd))
|
print(funct.ssh_command(serv, cmd))
|
||||||
sql.update_enable_waf_rules(rule_id, serv, enable)
|
sql.update_enable_waf_rules(rule_id, serv, enable)
|
||||||
|
|
||||||
|
|
||||||
|
if form.getvalue('lets_domain'):
|
||||||
|
serv = form.getvalue('serv')
|
||||||
|
lets_domain = form.getvalue('lets_domain')
|
||||||
|
lets_email = form.getvalue('lets_email')
|
||||||
|
proxy = sql.get_setting('proxy')
|
||||||
|
ssl_path = sql.get_setting('cert_path')
|
||||||
|
script = "letsencrypt.sh"
|
||||||
|
ssh_enable, ssh_user_name, ssh_user_password, ssh_key_name = funct.return_ssh_keys_path(serv)
|
||||||
|
|
||||||
|
if ssh_enable == 0:
|
||||||
|
ssh_key_name = ''
|
||||||
|
|
||||||
|
servers = sql.select_servers(server=serv)
|
||||||
|
for server in servers:
|
||||||
|
ssh_port = str(server[10])
|
||||||
|
|
||||||
|
os.system("cp scripts/%s ." % script)
|
||||||
|
|
||||||
|
if proxy is not None and proxy != '' and proxy != 'None':
|
||||||
|
proxy_serv = proxy
|
||||||
|
else:
|
||||||
|
proxy_serv = ''
|
||||||
|
|
||||||
|
commands = ["chmod +x "+script +" && ./"+script +" PROXY=" + proxy_serv+
|
||||||
|
" DOMAIN="+lets_domain+" EMAIL="+lets_email+" SSH_PORT="+ssh_port+" SSL_PATH="+ssl_path+
|
||||||
|
" HOST="+serv+" USER="+ssh_user_name+" PASS="+ssh_user_password+" KEY="+ssh_key_name]
|
||||||
|
|
||||||
|
output, error = funct.subprocess_execute(commands[0])
|
||||||
|
|
||||||
|
if error:
|
||||||
|
funct.logging('localhost', error, haproxywi=1)
|
||||||
|
print(error)
|
||||||
|
else:
|
||||||
|
for l in output:
|
||||||
|
if "msg" in l or "FAILED" in l:
|
||||||
|
try:
|
||||||
|
l = l.split(':')[1]
|
||||||
|
l = l.split('"')[1]
|
||||||
|
print(l+"<br>")
|
||||||
|
break
|
||||||
|
except:
|
||||||
|
print(output)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
print('success: Certificate has been created')
|
||||||
|
|
||||||
|
os.system("rm -f %s" % script)
|
|
@ -0,0 +1,48 @@
|
||||||
|
- hosts: "{{ variable_host }}"
|
||||||
|
become: yes
|
||||||
|
become_method: sudo
|
||||||
|
tasks:
|
||||||
|
|
||||||
|
- name: install EPEL Repository
|
||||||
|
yum:
|
||||||
|
name: epel-release
|
||||||
|
state: latest
|
||||||
|
when: (ansible_facts['os_family'] == "RedHat" or ansible_facts['os_family'] == 'CentOS')
|
||||||
|
ignore_errors: yes
|
||||||
|
failed_when: false
|
||||||
|
no_log: True
|
||||||
|
environment:
|
||||||
|
http_proxy: "{{PROXY}}"
|
||||||
|
https_proxy: "{{PROXY}}"
|
||||||
|
|
||||||
|
- name: Install certbot
|
||||||
|
package:
|
||||||
|
name: certbot
|
||||||
|
state: present
|
||||||
|
environment:
|
||||||
|
http_proxy: "{{PROXY}}"
|
||||||
|
https_proxy: "{{PROXY}}"
|
||||||
|
|
||||||
|
- name: Kill cerbot standalone
|
||||||
|
shell: ps ax |grep 'certbot certonly --standalone' |grep -v grep |awk '{print $1}' |xargs kill
|
||||||
|
ignore_errors: yes
|
||||||
|
failed_when: false
|
||||||
|
no_log: True
|
||||||
|
|
||||||
|
# - name: Get cert
|
||||||
|
# command: certbot certonly --standalone -d "{{DOMAIN}}" --non-interactive --agree-tos --email "{{EMAIL}}" --http-01-port=8888
|
||||||
|
|
||||||
|
- name: Combine into pem file
|
||||||
|
shell: cat /etc/letsencrypt/live/"{{DOMAIN}}"/fullchain.pem /etc/letsencrypt/live/"{{DOMAIN}}"/privkey.pem > "{{SSL_PATH}}"/"{{DOMAIN}}".pem
|
||||||
|
|
||||||
|
- name: Copy renew script
|
||||||
|
template:
|
||||||
|
src: /var/www/haproxy-wi/app/scripts/ansible/roles/renew_letsencrypt.j2
|
||||||
|
dest: /etc/haproxy/renew_letsencrypt.sh
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Creates cron jobs
|
||||||
|
cron:
|
||||||
|
name: "Let's encrypt renew script"
|
||||||
|
special_time: "monthly"
|
||||||
|
job: '/etc/haproxy/renew_letsencrypt.sh'
|
|
@ -0,0 +1,24 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
cd /etc/letsencrypt/live/
|
||||||
|
email='{{EMAIL}}'
|
||||||
|
path='{{SSL_PATH}}'
|
||||||
|
|
||||||
|
ps ax |grep 'certbot certonly --standalone' |grep -v grep |awk '{print $1}' |xargs kill
|
||||||
|
|
||||||
|
command='sudo certbot certonly --standalone'
|
||||||
|
|
||||||
|
for i in $(ls -d */ |awk -F"/" '{print $1}'); do
|
||||||
|
echo $i
|
||||||
|
command+=" -d "$i
|
||||||
|
done
|
||||||
|
|
||||||
|
command+=' --non-interactive --agree-tos --email $email --http-01-port=8888'
|
||||||
|
|
||||||
|
for i in $(ls -d */ |awk -F"/" '{print $1}'); do
|
||||||
|
bash -c "cat /etc/letsencrypt/live/$i/fullchain.pem /etc/letsencrypt/live/$i/privkey.pem > $path/$i.pem"
|
||||||
|
done
|
||||||
|
|
||||||
|
bash -c $command
|
||||||
|
# Reload HAProxy
|
||||||
|
sudo systemctl status haproxy
|
|
@ -0,0 +1,41 @@
|
||||||
|
#!/bin/bash
|
||||||
|
for ARGUMENT in "$@"
|
||||||
|
do
|
||||||
|
KEY=$(echo $ARGUMENT | cut -f1 -d=)
|
||||||
|
VALUE=$(echo $ARGUMENT | cut -f2 -d=)
|
||||||
|
|
||||||
|
case "$KEY" in
|
||||||
|
PROXY) PROXY=${VALUE} ;;
|
||||||
|
HOST) HOST=${VALUE} ;;
|
||||||
|
USER) USER=${VALUE} ;;
|
||||||
|
PASS) PASS=${VALUE} ;;
|
||||||
|
KEY) KEY=${VALUE} ;;
|
||||||
|
SSH_PORT) SSH_PORT=${VALUE} ;;
|
||||||
|
DOMAIN) DOMAIN=${VALUE} ;;
|
||||||
|
EMAIL) EMAIL=${VALUE} ;;
|
||||||
|
SSL_PATH) SSL_PATH=${VALUE} ;;
|
||||||
|
*)
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
export ANSIBLE_HOST_KEY_CHECKING=False
|
||||||
|
export ANSIBLE_DISPLAY_SKIPPED_HOSTS=False
|
||||||
|
export ACTION_WARNINGS=False
|
||||||
|
PWD=`pwd`
|
||||||
|
PWD=$PWD/scripts/ansible/
|
||||||
|
echo $HOST > $PWD/$HOST
|
||||||
|
|
||||||
|
if [[ $KEY == "" ]]; then
|
||||||
|
ansible-playbook $PWD/roles/letsencrypt.yml -e "ansible_user=$USER ansible_ssh_pass=$PASS ansible_port=$SSH_PORT variable_host=$HOST PROXY=$PROXY DOMAIN=$DOMAIN EMAIL=$EMAIL SSL_PATH=$SSL_PATH" -i $PWD/$HOST
|
||||||
|
else
|
||||||
|
ansible-playbook $PWD/roles/letsencrypt.yml --key-file $KEY -e "ansible_user=$USER ansible_port=$SSH_PORT variable_host=$HOST PROXY=$PROXY DOMAIN=$DOMAIN EMAIL=$EMAIL SSL_PATH=$SSL_PATH" -i $PWD/$HOST
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $? -gt 0 ]
|
||||||
|
then
|
||||||
|
echo "error: Can't create SSL certificate"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo "ok"
|
||||||
|
fi
|
||||||
|
rm -f $PWD/$HOST
|
11
app/sql.py
11
app/sql.py
|
@ -206,6 +206,7 @@ def add_setting_for_new_group(group_id):
|
||||||
sql.append("INSERT INTO settings (param, value, section, `desc`, `group`) values('ldap_user_attribute', 'sAMAccountName', 'ldap', 'User attribute for search', " + group_id + ");")
|
sql.append("INSERT INTO settings (param, value, section, `desc`, `group`) values('ldap_user_attribute', 'sAMAccountName', 'ldap', 'User attribute for search', " + group_id + ");")
|
||||||
sql.append("INSERT INTO settings (param, value, section, `desc`, `group`) values('ldap_search_field', 'mail', 'ldap', 'Field where user e-mail saved', " + group_id + ");")
|
sql.append("INSERT INTO settings (param, value, section, `desc`, `group`) values('ldap_search_field', 'mail', 'ldap', 'Field where user e-mail saved', " + group_id + ");")
|
||||||
sql.append("INSERT INTO settings (param, value, section, `desc`, `group`) values('ldap_type', '0', 'ldap', 'If 0 then will be used LDAP, if 1 then will be used LDAPS ', " + group_id + ");")
|
sql.append("INSERT INTO settings (param, value, section, `desc`, `group`) values('ldap_type', '0', 'ldap', 'If 0 then will be used LDAP, if 1 then will be used LDAPS ', " + group_id + ");")
|
||||||
|
sql.append("INSERT INTO settings (param, value, section, `desc`, `group`) values('haproxy_enterprise', '0', 'haproxy', 'Use this option if your HAProxy is enterprise. It change service name for rebooting/reloading', " + group_id + ");")
|
||||||
|
|
||||||
for i in sql:
|
for i in sql:
|
||||||
try:
|
try:
|
||||||
|
@ -2165,12 +2166,12 @@ def smon_list(user_group):
|
||||||
return cur.fetchall()
|
return cur.fetchall()
|
||||||
|
|
||||||
|
|
||||||
def insert_alerts(user_group, message):
|
def insert_alerts(user_group, level, ip, port, message, service):
|
||||||
con, cur = get_cur()
|
con, cur = get_cur()
|
||||||
if mysql_enable == '1':
|
if mysql_enable == '1':
|
||||||
sql = """ insert into alerts (user_group, message, date) values('%s', '%s', now()) """ % (user_group, message)
|
sql = """ insert into alerts (user_group, message, level, ip, port, service, date) values('%s', '%s', '%s', '%s', '%s', '%s', now()) """ % (user_group, message, level, ip, port, service)
|
||||||
else:
|
else:
|
||||||
sql = """ insert into alerts (user_group, message, date) values('%s', '%s', datetime('now', 'localtime')) """ % (user_group, message)
|
sql = """ insert into alerts (user_group, message, level, ip, port, service, date) values('%s', '%s', '%s', '%s', '%s', '%s', datetime('now', 'localtime')) """ % (user_group, message, level, ip, port, service)
|
||||||
try:
|
try:
|
||||||
cur.execute(sql)
|
cur.execute(sql)
|
||||||
con.commit()
|
con.commit()
|
||||||
|
@ -2184,9 +2185,9 @@ def insert_alerts(user_group, message):
|
||||||
def select_alerts(user_group):
|
def select_alerts(user_group):
|
||||||
con, cur = get_cur()
|
con, cur = get_cur()
|
||||||
if mysql_enable == '1':
|
if mysql_enable == '1':
|
||||||
sql = """ select message, `date` from alerts where user_group = '%s' and `date` <= (now()+ INTERVAL 10 second) """ % (user_group)
|
sql = """ select level, message, `date` from alerts where user_group = '%s' and `date` <= (now()+ INTERVAL 10 second) """ % (user_group)
|
||||||
else:
|
else:
|
||||||
sql = """ select message, `date` from alerts where user_group = '%s' and `date` >= datetime('now', '-20 second', 'localtime') and `date` <= datetime('now', 'localtime') ; """ % (user_group)
|
sql = """ select level, message, `date` from alerts where user_group = '%s' and `date` >= datetime('now', '-20 second', 'localtime') and `date` <= datetime('now', 'localtime') ; """ % (user_group)
|
||||||
try:
|
try:
|
||||||
cur.execute(sql)
|
cur.execute(sql)
|
||||||
except sqltool.Error as e:
|
except sqltool.Error as e:
|
||||||
|
|
|
@ -526,6 +526,7 @@ h3 {
|
||||||
|
|
||||||
<div id="ssl">
|
<div id="ssl">
|
||||||
<table>
|
<table>
|
||||||
|
<caption><h3>SSL</h3></caption>
|
||||||
<tr class="overviewHead">
|
<tr class="overviewHead">
|
||||||
<td class="padding10 first-collumn" style="width: 30%;">View certificates</td>
|
<td class="padding10 first-collumn" style="width: 30%;">View certificates</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -546,7 +547,6 @@ h3 {
|
||||||
<span id="ajax-show-ssl"></span>
|
<span id="ajax-show-ssl"></span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<table>
|
|
||||||
<tr class="overviewHead">
|
<tr class="overviewHead">
|
||||||
<td class="padding10 first-collumn" style="width: 30%;">Upload SSL certificates</td>
|
<td class="padding10 first-collumn" style="width: 30%;">Upload SSL certificates</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -574,6 +574,40 @@ h3 {
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
<table>
|
||||||
|
<caption><h3>Let's Encrypt</h3></caption>
|
||||||
|
<tr class="overviewHead">
|
||||||
|
<td class="padding10 first-collumn">
|
||||||
|
Server
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
Domain name
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
E-mail
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="padding10 first-collumn">
|
||||||
|
<select required id="serv_for_lets">
|
||||||
|
<option disabled selected>Choose server</option>
|
||||||
|
{% for select in selects %}
|
||||||
|
<option value="{{ select.2 }}">{{ select.1 }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ input('lets_domain', placeholder="example.com") }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ input('lets_email') }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button id="lets_button">Get certificate</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
<div id="ajax-ssl"></div>
|
<div id="ajax-ssl"></div>
|
||||||
</div>
|
</div>
|
||||||
<div id="option">
|
<div id="option">
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
{
|
{
|
||||||
"searchable": false,
|
"searchable": false,
|
||||||
"orderable": false,
|
"orderable": false,
|
||||||
"targets": {{headers|length - 1 }}
|
"targets": -1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
|
"lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
{
|
{
|
||||||
"searchable": false,
|
"searchable": false,
|
||||||
"orderable": false,
|
"orderable": false,
|
||||||
"targets": {{headers|length - 1 }}
|
"targets": -1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
|
"lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
<li><a href="#ip" title="Runtime API: Changing IP and Port for backend servers - HAProxy-WI">Change IP and Port</a></li>
|
<li><a href="#ip" title="Runtime API: Changing IP and Port for backend servers - HAProxy-WI">Change IP and Port</a></li>
|
||||||
<li><a href="#table" title="Runtime API: Stick Table - HAProxy-WI">Stick Table</a></li>
|
<li><a href="#table" title="Runtime API: Stick Table - HAProxy-WI">Stick Table</a></li>
|
||||||
<li><a href="#lists" title="Runtime API: Change dynamically whitelist and blacklist - HAProxy-WI">Lists</a></li>
|
<li><a href="#lists" title="Runtime API: Change dynamically whitelist and blacklist - HAProxy-WI">Lists</a></li>
|
||||||
|
<li><a href="#sessions" title="Runtime API: Sessions - HAProxy-WI">Sessions</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% include 'include/login.html' %}
|
{% include 'include/login.html' %}
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -35,6 +36,7 @@
|
||||||
<option disabled>Choose action</option>
|
<option disabled>Choose action</option>
|
||||||
{% if role <= 2 %}
|
{% if role <= 2 %}
|
||||||
<option value="disable">Disable</option>
|
<option value="disable">Disable</option>
|
||||||
|
<option value="shutdown">Shutdown</option>
|
||||||
<option value="enable">Enable</option>
|
<option value="enable">Enable</option>
|
||||||
<option value="set">Set</option>
|
<option value="set">Set</option>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -217,8 +219,38 @@
|
||||||
You can read how it works <a href="https://haproxy-wi.org/description.py?description=runtimeapi#lists" title="Manage lists" target="_blank">here</a>
|
You can read how it works <a href="https://haproxy-wi.org/description.py?description=runtimeapi#lists" title="Manage lists" target="_blank">here</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="sessions">
|
||||||
|
<table class="overview">
|
||||||
|
<tr class="overviewHead">
|
||||||
|
<td class="padding10 first-collumn">Server</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="padding10 first-collumn" style="width: 25%;">
|
||||||
|
<form action="" method="post" id="runtimeapisessions">
|
||||||
|
<select autofocus required name="sessions_serv_select" id="sessions_serv_select">
|
||||||
|
<option disabled selected>Choose server</option>
|
||||||
|
{% for select in selects %}
|
||||||
|
<option value="{{ select.2 }}">{{ select.1 }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="submit" name="Enter" value="Enter" id="enter">Get sessions</button>
|
||||||
|
</td>
|
||||||
|
</form>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<div id="ajaxsessions"></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#lists" title="Manage lists" target="_blank">here</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
<div id="get-session-info" title="View session" style="display: none;">
|
||||||
|
<pre id="get-session-info-body"></pre>
|
||||||
|
</div>
|
||||||
<script>
|
<script>
|
||||||
$( function() {
|
$( function() {
|
||||||
if (window.matchMedia('(max-width: 1280px)').matches) {
|
if (window.matchMedia('(max-width: 1280px)').matches) {
|
||||||
|
|
|
@ -1,60 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
import subprocess
|
|
||||||
from subprocess import check_output, CalledProcessError
|
|
||||||
import time
|
|
||||||
import os, sys
|
|
||||||
sys.path.append(os.path.join(sys.path[0], os.path.dirname(os.getcwd())))
|
|
||||||
sys.path.append(os.path.join(sys.path[0], os.getcwd()))
|
|
||||||
import funct
|
|
||||||
import sql
|
|
||||||
import signal
|
|
||||||
|
|
||||||
class GracefulKiller:
|
|
||||||
kill_now = False
|
|
||||||
def __init__(self):
|
|
||||||
signal.signal(signal.SIGINT, self.exit_gracefully)
|
|
||||||
signal.signal(signal.SIGTERM, self.exit_gracefully)
|
|
||||||
|
|
||||||
def exit_gracefully(self,signum, frame):
|
|
||||||
self.kill_now = True
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
port = sql.get_setting('haproxy_sock_port')
|
|
||||||
readstats = ""
|
|
||||||
killer = GracefulKiller()
|
|
||||||
|
|
||||||
while True:
|
|
||||||
servers = sql.select_keep_alive()
|
|
||||||
for serv in servers:
|
|
||||||
try:
|
|
||||||
readstats = subprocess.check_output(["echo show stat | nc "+serv[0]+" "+port], shell=True)
|
|
||||||
except CalledProcessError as e:
|
|
||||||
alert = "Try to start HAProxy serivce on " + serv[0]
|
|
||||||
funct.logging("localhost", " "+alert, keep_alive=1)
|
|
||||||
|
|
||||||
start_command = []
|
|
||||||
start_command.append('sudo systemctl restart haproxy')
|
|
||||||
funct.ssh_command(serv[0], start_command)
|
|
||||||
|
|
||||||
time.sleep(30)
|
|
||||||
continue
|
|
||||||
except OSError as e:
|
|
||||||
print(e)
|
|
||||||
sys.exit()
|
|
||||||
else:
|
|
||||||
cur_stat_service = "Ok"
|
|
||||||
time.sleep(30)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
funct.logging("localhost", " Keep alive service is started", keep_alive=1)
|
|
||||||
killer = GracefulKiller()
|
|
||||||
|
|
||||||
while True:
|
|
||||||
main()
|
|
||||||
time.sleep(60)
|
|
||||||
|
|
||||||
if killer.kill_now:
|
|
||||||
break
|
|
||||||
|
|
||||||
funct.logging("localhost", " Keep alive service is shutdown", keep_alive=1)
|
|
|
@ -1,9 +0,0 @@
|
||||||
/var/www/haproxy-wi/log/keep_alive.log {
|
|
||||||
daily
|
|
||||||
rotate 10
|
|
||||||
missingok
|
|
||||||
notifempty
|
|
||||||
create 0644 apache apache
|
|
||||||
dateext
|
|
||||||
sharedscripts
|
|
||||||
}
|
|
|
@ -1,2 +0,0 @@
|
||||||
if $programname startswith 'keep_alive' then /var/www/haproxy-wi/log/keep_alive.log
|
|
||||||
& stop
|
|
|
@ -1,19 +0,0 @@
|
||||||
[Unit]
|
|
||||||
Description=Keep Alive Haproxy
|
|
||||||
After=syslog.target network.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
WorkingDirectory=/var/www/haproxy-wi/app/
|
|
||||||
ExecStart=/var/www/haproxy-wi/app/tools/keep_alive.py
|
|
||||||
|
|
||||||
StandardOutput=syslog
|
|
||||||
StandardError=syslog
|
|
||||||
SyslogIdentifier=keep_alive
|
|
||||||
|
|
||||||
RestartSec=2s
|
|
||||||
Restart=on-failure
|
|
||||||
TimeoutStopSec=1s
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
36
inc/add.js
36
inc/add.js
|
@ -1,6 +1,7 @@
|
||||||
var ssl_offloading_var = "http-request set-header X-Forwarded-Port %[dst_port] \n"+
|
var ssl_offloading_var = "http-request set-header X-Forwarded-Port %[dst_port] \n"+
|
||||||
"http-request add-header X-Forwarded-Proto https if { ssl_fc } \n"+
|
"http-request add-header X-Forwarded-Proto https if { ssl_fc } \n"+
|
||||||
"redirect scheme https if !{ ssl_fc } \n"
|
"redirect scheme https if !{ ssl_fc } \n"
|
||||||
|
|
||||||
$( function() {
|
$( function() {
|
||||||
$( "#listen-mode-select" ).on('selectmenuchange',function() {
|
$( "#listen-mode-select" ).on('selectmenuchange',function() {
|
||||||
if ($( "#listen-mode-select option:selected" ).val() == "tcp") {
|
if ($( "#listen-mode-select option:selected" ).val() == "tcp") {
|
||||||
|
@ -850,6 +851,41 @@ $( function() {
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
});
|
});
|
||||||
|
$('#lets_button').click(function() {
|
||||||
|
var lets_domain = $('#lets_domain').val();
|
||||||
|
var lets_email = $('#lets_email').val();
|
||||||
|
if (lets_email == '' || lets_domain == '') {
|
||||||
|
toastr.error('Fields cannot be empty');
|
||||||
|
} else if (validateEmail(lets_email)) {
|
||||||
|
$("#ajax-ssl").html(wait_mess);
|
||||||
|
$.ajax({
|
||||||
|
url: "options.py",
|
||||||
|
data: {
|
||||||
|
serv: $('#serv_for_lets').val(),
|
||||||
|
lets_domain: lets_domain,
|
||||||
|
lets_email: lets_email,
|
||||||
|
token: $('#token').val()
|
||||||
|
},
|
||||||
|
type: "POST",
|
||||||
|
success: function (data) {
|
||||||
|
if (data.indexOf('error:') != '-1' || data.indexOf('ERROR') != '-1' || data.indexOf('FAILED') != '-1') {
|
||||||
|
toastr.clear();
|
||||||
|
toastr.error(data);
|
||||||
|
} else if (data.indexOf('WARNING') != '-1') {
|
||||||
|
toastr.clear();
|
||||||
|
toastr.warning(data);
|
||||||
|
} else {
|
||||||
|
toastr.clear();
|
||||||
|
toastr.success(data);
|
||||||
|
}
|
||||||
|
$("#ajax-ssl").html('');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
toastr.clear();
|
||||||
|
toastr.error('Wrong e-mail format');
|
||||||
|
}
|
||||||
|
});
|
||||||
var add_server_var = '<br /><input name="servers" title="Backend IP" size=14 placeholder="xxx.xxx.xxx.xxx" class="form-control">: <input name="server_port" title="Backend port" size=1 placeholder="yyy" class="form-control">'
|
var add_server_var = '<br /><input name="servers" title="Backend IP" size=14 placeholder="xxx.xxx.xxx.xxx" class="form-control">: <input name="server_port" title="Backend port" size=1 placeholder="yyy" class="form-control">'
|
||||||
$('[name=add-server-input]').click(function() {
|
$('[name=add-server-input]').click(function() {
|
||||||
$("[name=add_servers]").append(add_server_var);
|
$("[name=add_servers]").append(add_server_var);
|
||||||
|
|
|
@ -59,6 +59,20 @@ function renderChart(data, labels, server) {
|
||||||
ticks: {
|
ticks: {
|
||||||
beginAtZero: true,
|
beginAtZero: true,
|
||||||
}
|
}
|
||||||
|
}],
|
||||||
|
xAxes: [{
|
||||||
|
offset: true,
|
||||||
|
ticks: {
|
||||||
|
major: {
|
||||||
|
enabled: true,
|
||||||
|
fontStyle: 'bold'
|
||||||
|
},
|
||||||
|
source: 'data',
|
||||||
|
autoSkip: true,
|
||||||
|
autoSkipPadding:45,
|
||||||
|
maxRotation: 0,
|
||||||
|
sampleSize: 100
|
||||||
|
}
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
|
@ -119,6 +133,19 @@ function renderWafChart(data, labels, server) {
|
||||||
ticks: {
|
ticks: {
|
||||||
beginAtZero: true,
|
beginAtZero: true,
|
||||||
}
|
}
|
||||||
|
}],
|
||||||
|
xAxes: [{
|
||||||
|
ticks: {
|
||||||
|
major: {
|
||||||
|
enabled: true,
|
||||||
|
fontStyle: 'bold'
|
||||||
|
},
|
||||||
|
source: 'data',
|
||||||
|
autoSkip: true,
|
||||||
|
autoSkipPadding: 45,
|
||||||
|
maxRotation: 0,
|
||||||
|
sampleSize: 100
|
||||||
|
}
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
|
|
|
@ -229,6 +229,10 @@ $( function() {
|
||||||
getList();
|
getList();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
$('#runtimeapisessions').submit(function() {
|
||||||
|
getSessions();
|
||||||
|
return false;
|
||||||
|
});
|
||||||
$( "#list_serv_select" ).on('selectmenuchange',function() {
|
$( "#list_serv_select" ).on('selectmenuchange',function() {
|
||||||
$.ajax( {
|
$.ajax( {
|
||||||
url: "options.py",
|
url: "options.py",
|
||||||
|
@ -411,3 +415,77 @@ function addNewIp() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function getSessions() {
|
||||||
|
$.ajax( {
|
||||||
|
url: "options.py",
|
||||||
|
data: {
|
||||||
|
sessions_select: $('#sessions_serv_select').val(),
|
||||||
|
token: $('#token').val()
|
||||||
|
},
|
||||||
|
type: "POST",
|
||||||
|
success: function( data ) {
|
||||||
|
if (data.indexOf('error: ') != '-1') {
|
||||||
|
toastr.error(data);
|
||||||
|
} else {
|
||||||
|
$("#ajaxsessions").html(data);
|
||||||
|
$( "input[type=submit], button" ).button();
|
||||||
|
$.getScript("/inc/fontawesome.min.js");
|
||||||
|
FontAwesomeConfig = { searchPseudoElements: true, observeMutations: false };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
function getSessionInfo(sess_id) {
|
||||||
|
$.ajax( {
|
||||||
|
url: "options.py",
|
||||||
|
data: {
|
||||||
|
sessions_select_show: $('#sessions_serv_select').val(),
|
||||||
|
sessions_select_id: sess_id,
|
||||||
|
token: $('#token').val()
|
||||||
|
},
|
||||||
|
type: "POST",
|
||||||
|
success: function( data ) {
|
||||||
|
if (data.indexOf('danger') != '-1') {
|
||||||
|
toastr.error(data);
|
||||||
|
} else {
|
||||||
|
toastr.clear();
|
||||||
|
$("#get-session-info-body").html(data);
|
||||||
|
$( "#get-session-info" ).dialog({
|
||||||
|
resizable: false,
|
||||||
|
height: "auto",
|
||||||
|
width: 760,
|
||||||
|
modal: true,
|
||||||
|
title: "View session",
|
||||||
|
buttons: {
|
||||||
|
Close: function() {
|
||||||
|
$( this ).dialog( "close" );
|
||||||
|
$("#get-session-info-body").html('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
function deleteSession(id, sess_id) {
|
||||||
|
toastr.clear();
|
||||||
|
$(id).parent().parent().css("background-color", "#f2dede !important");
|
||||||
|
$.ajax( {
|
||||||
|
url: "options.py",
|
||||||
|
data: {
|
||||||
|
serv: $('#sessions_serv_select').val(),
|
||||||
|
session_delete_id: sess_id,
|
||||||
|
token: $('#token').val()
|
||||||
|
},
|
||||||
|
type: "POST",
|
||||||
|
success: function( data ) {
|
||||||
|
if (data.indexOf('error: ') != '-1') {
|
||||||
|
toastr.error(data);
|
||||||
|
} else {
|
||||||
|
$(id).parent().parent().remove();
|
||||||
|
toastr.success('The sessions has been deleted');
|
||||||
|
getSessions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
|
@ -2,7 +2,11 @@ var url = "/inc/script.js";
|
||||||
var cur_url = window.location.href.split('/').pop();
|
var cur_url = window.location.href.split('/').pop();
|
||||||
cur_url = cur_url.split('?');
|
cur_url = cur_url.split('?');
|
||||||
var intervalId;
|
var intervalId;
|
||||||
|
function validateEmail(email) {
|
||||||
|
const re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
||||||
|
return re.test(email);
|
||||||
|
}
|
||||||
|
var wait_mess = '<div class="alert alert-warning">Please don\'t close and don\'t represh page. Wait until the work is completed. This may take some time </div>'
|
||||||
$( function() {
|
$( function() {
|
||||||
$('.menu li ul li').each(function () {
|
$('.menu li ul li').each(function () {
|
||||||
var link = $(this).find('a').attr('href');
|
var link = $(this).find('a').attr('href');
|
||||||
|
@ -1149,3 +1153,4 @@ function checkLength( o, n, min ) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue