mirror of https://github.com/midoks/mdserver-web
parent
528094cfa7
commit
5aeaf13f16
@ -0,0 +1,2 @@ |
||||
## 指定共享内存 |
||||
lua_shared_dict healthcheck 10m; |
@ -0,0 +1,64 @@ |
||||
location / { |
||||
proxy_pass http://{$UPSTREAM_NAME}; |
||||
|
||||
client_max_body_size 10m; |
||||
client_body_buffer_size 128k; |
||||
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; |
||||
proxy_set_header X-Real-IP $remote_addr; |
||||
proxy_set_header Host $proxy_host; |
||||
proxy_connect_timeout 90; |
||||
proxy_send_timeout 90; |
||||
proxy_read_timeout 90; |
||||
proxy_buffer_size 4k; |
||||
proxy_buffers 4 32k; |
||||
proxy_busy_buffers_size 64k; |
||||
proxy_temp_file_write_size 64k; |
||||
} |
||||
|
||||
|
||||
#location /upstream_status { |
||||
# allow 127.0.0.1; |
||||
# deny all; |
||||
# access_log off; |
||||
# default_type text/plain; |
||||
# content_by_lua_block { |
||||
# local hc = require "resty.upstream.healthcheck" |
||||
# ngx.say("OpenResty Worker PID: ", ngx.worker.pid()) |
||||
# ngx.print(hc.status_page()) |
||||
# } |
||||
#} |
||||
|
||||
location /upstream_status_{$UPSTREAM_NAME} { |
||||
allow 127.0.0.1; |
||||
deny all; |
||||
access_log off; |
||||
default_type text/plain; |
||||
content_by_lua_block { |
||||
local json = require "cjson" |
||||
local ok, upstream = pcall(require, "ngx.upstream") |
||||
if not ok then |
||||
ngx.print("[]") |
||||
return |
||||
end |
||||
|
||||
local get_primary_peers = upstream.get_primary_peers |
||||
local get_backup_peers = upstream.get_backup_peers |
||||
local upstream_name = "{$UPSTREAM_NAME}" |
||||
|
||||
peers, err = get_primary_peers(upstream_name) |
||||
if not peers then |
||||
ngx.print("[]") |
||||
return |
||||
end |
||||
|
||||
peers_backup, err = get_backup_peers(upstream_name) |
||||
if peers_backup then |
||||
for k, v in pairs(peers_backup) do |
||||
table.insert(peers,v) |
||||
end |
||||
end |
||||
|
||||
ngx.print(json.encode(peers)) |
||||
} |
||||
} |
@ -0,0 +1,5 @@ |
||||
upstream {$UPSTREAM_NAME} |
||||
{ |
||||
{$NODE_ALGO} |
||||
{$NODE_SERVER_LIST} |
||||
} |
After Width: | Height: | Size: 853 B |
@ -0,0 +1,21 @@ |
||||
<div class="bt-form"> |
||||
<div class="bt-w-main"> |
||||
<div class="bt-w-menu"> |
||||
<p class="bgw" onclick="pluginService('op_load_balance');">服务</p> |
||||
<p onclick="loadBalanceList();">负载均衡</p> |
||||
</div> |
||||
<div class="bt-w-con pd15"> |
||||
<div class="soft-man-con"></div> |
||||
</div> |
||||
</div> |
||||
|
||||
</div> |
||||
|
||||
<script type="text/javascript" src="/plugins/file?name=op_load_balance&f=js/app.js"></script> |
||||
<script type="text/javascript"> |
||||
resetPluginWinWidth(800); |
||||
resetPluginWinHeight(300); |
||||
$.getScript( "/plugins/file?name=op_load_balance&f=js/app.js", function(){ |
||||
pluginService('op_load_balance'); |
||||
}); |
||||
</script> |
@ -0,0 +1,474 @@ |
||||
# coding:utf-8 |
||||
|
||||
import sys |
||||
import io |
||||
import os |
||||
import time |
||||
import subprocess |
||||
import json |
||||
import re |
||||
|
||||
sys.path.append(os.getcwd() + "/class/core") |
||||
import mw |
||||
|
||||
|
||||
app_debug = False |
||||
if mw.isAppleSystem(): |
||||
app_debug = True |
||||
|
||||
|
||||
def getPluginName(): |
||||
return 'op_load_balance' |
||||
|
||||
|
||||
def getPluginDir(): |
||||
return mw.getPluginDir() + '/' + getPluginName() |
||||
|
||||
|
||||
def getServerDir(): |
||||
return mw.getServerDir() + '/' + getPluginName() |
||||
|
||||
|
||||
def getArgs(): |
||||
args = sys.argv[2:] |
||||
tmp = {} |
||||
args_len = len(args) |
||||
|
||||
if args_len == 1: |
||||
t = args[0].strip('{').strip('}') |
||||
if t.strip() == '': |
||||
tmp = [] |
||||
else: |
||||
t = t.split(':') |
||||
tmp[t[0]] = t[1] |
||||
tmp[t[0]] = t[1] |
||||
elif args_len > 1: |
||||
for i in range(len(args)): |
||||
t = args[i].split(':') |
||||
tmp[t[0]] = t[1] |
||||
return tmp |
||||
|
||||
|
||||
def checkArgs(data, ck=[]): |
||||
for i in range(len(ck)): |
||||
if not ck[i] in data: |
||||
return (False, mw.returnJson(False, '参数:(' + ck[i] + ')没有!')) |
||||
return (True, mw.returnJson(True, 'ok')) |
||||
|
||||
|
||||
def getConf(): |
||||
path = getServerDir() + "/cfg.json" |
||||
|
||||
if not os.path.exists(path): |
||||
mw.writeFile(path, '[]') |
||||
|
||||
c = mw.readFile(path) |
||||
return json.loads(c) |
||||
|
||||
|
||||
def writeConf(data): |
||||
path = getServerDir() + "/cfg.json" |
||||
mw.writeFile(path, json.dumps(data)) |
||||
|
||||
|
||||
def contentReplace(content): |
||||
service_path = mw.getServerDir() |
||||
content = content.replace('{$ROOT_PATH}', mw.getRootDir()) |
||||
content = content.replace('{$SERVER_PATH}', service_path) |
||||
content = content.replace('{$APP_PATH}', app_path) |
||||
return content |
||||
|
||||
|
||||
def restartWeb(): |
||||
mw.opWeb('stop') |
||||
mw.opWeb('start') |
||||
|
||||
|
||||
def loadBalanceConf(): |
||||
path = mw.getServerDir() + '/web_conf/nginx/vhost/load_balance.conf' |
||||
return path |
||||
|
||||
|
||||
def initDreplace(): |
||||
|
||||
dst_conf_tpl = getPluginDir() + '/conf/load_balance.conf' |
||||
dst_conf = loadBalanceConf() |
||||
|
||||
if not os.path.exists(dst_conf): |
||||
con = mw.readFile(dst_conf_tpl) |
||||
mw.writeFile(dst_conf, con) |
||||
|
||||
|
||||
def status(): |
||||
if not mw.getWebStatus(): |
||||
return 'stop' |
||||
|
||||
dst_conf = loadBalanceConf() |
||||
if not os.path.exists(dst_conf): |
||||
return 'stop' |
||||
|
||||
return 'start' |
||||
|
||||
|
||||
def start(): |
||||
initDreplace() |
||||
restartWeb() |
||||
return 'ok' |
||||
|
||||
|
||||
def stop(): |
||||
dst_conf = loadBalanceConf() |
||||
os.remove(dst_conf) |
||||
|
||||
deleteLoadBalanceAllCfg() |
||||
restartWeb() |
||||
return 'ok' |
||||
|
||||
|
||||
def restart(): |
||||
restartWeb() |
||||
return 'ok' |
||||
|
||||
|
||||
def reload(): |
||||
restartWeb() |
||||
return 'ok' |
||||
|
||||
|
||||
def installPreInspection(): |
||||
check_op = mw.getServerDir() + "/openresty" |
||||
if not os.path.exists(check_op): |
||||
return "请先安装OpenResty" |
||||
return 'ok' |
||||
|
||||
|
||||
def deleteLoadBalanceAllCfg(): |
||||
cfg = getConf() |
||||
upstream_dir = mw.getServerDir() + '/web_conf/nginx/upstream' |
||||
lua_dir = mw.getServerDir() + '/web_conf/nginx/lua/init_worker_by_lua_file' |
||||
rewrite_dir = mw.getServerDir() + '/web_conf/nginx/rewrite' |
||||
vhost_dir = mw.getServerDir() + '/web_conf/nginx/vhost' |
||||
|
||||
for conf in cfg: |
||||
upstream_file = upstream_dir + '/' + conf['upstream_name'] + '.conf' |
||||
if os.path.exists(upstream_file): |
||||
os.remove(upstream_file) |
||||
|
||||
lua_file = lua_dir + '/' + conf['upstream_name'] + '.lua' |
||||
if os.path.exists(lua_file): |
||||
os.remove(lua_file) |
||||
|
||||
rewrite_file = rewrite_dir + '/' + conf['domain'] + '.conf' |
||||
mw.writeFile(rewrite_file, '') |
||||
|
||||
path = vhost_dir + '/' + conf['domain'] + '.conf' |
||||
|
||||
content = mw.readFile(path) |
||||
content = re.sub('include ' + upstream_file + ';' + "\n", '', content) |
||||
mw.writeFile(path, content) |
||||
|
||||
mw.opLuaInitWorkerFile() |
||||
|
||||
|
||||
def makeConfServerList(data): |
||||
slist = '' |
||||
for x in data: |
||||
slist += 'server ' |
||||
slist += x['ip'] + ':' + x['port'] |
||||
|
||||
if x['state'] == '0': |
||||
slist += ' down;\n\t' |
||||
continue |
||||
|
||||
if x['state'] == '2': |
||||
slist += ' backup;\n\t' |
||||
continue |
||||
|
||||
slist += ' weight=' + x['weight'] |
||||
slist += ' max_fails=' + x['max_fails'] |
||||
slist += ' fail_timeout=' + x['fail_timeout'] + "s;\n\t" |
||||
return slist |
||||
|
||||
|
||||
def makeLoadBalanceAllCfg(row): |
||||
# 生成所有配置 |
||||
cfg = getConf() |
||||
|
||||
upstream_dir = mw.getServerDir() + '/web_conf/nginx/upstream' |
||||
rewrite_dir = mw.getServerDir() + '/web_conf/nginx/rewrite' |
||||
vhost_dir = mw.getServerDir() + '/web_conf/nginx/vhost' |
||||
upstream_tpl = getPluginDir() + '/conf/upstream.tpl.conf' |
||||
rewrite_tpl = getPluginDir() + '/conf/rewrite.tpl.conf' |
||||
|
||||
if not os.path.exists(upstream_dir): |
||||
os.makedirs(upstream_dir) |
||||
|
||||
conf = cfg[row] |
||||
|
||||
# replace vhost start |
||||
vhost_file = vhost_dir + '/' + conf['domain'] + '.conf' |
||||
vcontent = mw.readFile(vhost_file) |
||||
|
||||
vhost_find_str = 'upstream/' + conf['upstream_name'] + '.conf' |
||||
vhead = 'include ' + mw.getServerDir() + '/web_conf/nginx/' + \ |
||||
vhost_find_str + ';' |
||||
|
||||
vpos = vcontent.find(vhost_find_str) |
||||
if vpos < 0: |
||||
vcontent = vhead + "\n" + vcontent |
||||
mw.writeFile(vhost_file, vcontent) |
||||
# replace vhost end |
||||
|
||||
# make upstream start |
||||
upstream_file = upstream_dir + '/' + conf['upstream_name'] + '.conf' |
||||
content = '' |
||||
if len(conf['node_list']) > 0: |
||||
content = mw.readFile(upstream_tpl) |
||||
slist = makeConfServerList(conf['node_list']) |
||||
content = content.replace('{$NODE_SERVER_LIST}', slist) |
||||
content = content.replace('{$UPSTREAM_NAME}', conf['upstream_name']) |
||||
if conf['node_algo'] != 'polling': |
||||
content = content.replace('{$NODE_ALGO}', conf['node_algo'] + ';') |
||||
else: |
||||
content = content.replace('{$NODE_ALGO}', '') |
||||
mw.writeFile(upstream_file, content) |
||||
# make upstream end |
||||
|
||||
# make rewrite start |
||||
rewrite_file = rewrite_dir + '/' + conf['domain'] + '.conf' |
||||
rcontent = '' |
||||
if len(conf['node_list']) > 0: |
||||
rcontent = mw.readFile(rewrite_tpl) |
||||
rcontent = rcontent.replace('{$UPSTREAM_NAME}', conf['upstream_name']) |
||||
mw.writeFile(rewrite_file, rcontent) |
||||
# make rewrite end |
||||
|
||||
# health check start |
||||
lua_dir = mw.getServerDir() + '/web_conf/nginx/lua/init_worker_by_lua_file' |
||||
lua_init_worker_file = lua_dir + '/' + conf['upstream_name'] + '.lua' |
||||
if conf['node_health_check'] == 'ok': |
||||
lua_dir_tpl = getPluginDir() + '/lua/health_check.lua.tpl' |
||||
content = mw.readFile(lua_dir_tpl) |
||||
content = content.replace('{$UPSTREAM_NAME}', conf['upstream_name']) |
||||
content = content.replace('{$DOMAIN}', conf['domain']) |
||||
mw.writeFile(lua_init_worker_file, content) |
||||
else: |
||||
if os.path.exists(lua_init_worker_file): |
||||
os.remove(lua_init_worker_file) |
||||
|
||||
mw.opLuaInitWorkerFile() |
||||
# health check end |
||||
return True |
||||
|
||||
|
||||
def add_load_balance(args): |
||||
|
||||
data = checkArgs( |
||||
args, ['domain', 'upstream_name', 'node_algo', 'node_list', 'node_health_check']) |
||||
if not data[0]: |
||||
return data[1] |
||||
|
||||
domain_json = args['domain'] |
||||
|
||||
tmp = json.loads(domain_json) |
||||
domain = tmp['domain'] |
||||
|
||||
cfg = getConf() |
||||
cfg_len = len(cfg) |
||||
tmp = {} |
||||
tmp['domain'] = domain |
||||
tmp['data'] = args['domain'] |
||||
tmp['upstream_name'] = args['upstream_name'] |
||||
tmp['node_algo'] = args['node_algo'] |
||||
tmp['node_list'] = args['node_list'] |
||||
tmp['node_health_check'] = args['node_health_check'] |
||||
cfg.append(tmp) |
||||
writeConf(cfg) |
||||
|
||||
import site_api |
||||
sobj = site_api.site_api() |
||||
domain_path = mw.getWwwDir() + '/' + domain |
||||
|
||||
ps = '负载均衡[' + domain + ']' |
||||
data = sobj.add(domain_json, '80', ps, domain_path, '00') |
||||
|
||||
makeLoadBalanceAllCfg(cfg_len) |
||||
mw.restartWeb() |
||||
return mw.returnJson(True, '添加成功', data) |
||||
|
||||
|
||||
def edit_load_balance(args): |
||||
data = checkArgs( |
||||
args, ['row', 'node_algo', 'node_list', 'node_health_check']) |
||||
if not data[0]: |
||||
return data[1] |
||||
|
||||
row = int(args['row']) |
||||
|
||||
cfg = getConf() |
||||
tmp = cfg[row] |
||||
tmp['node_algo'] = args['node_algo'] |
||||
tmp['node_list'] = args['node_list'] |
||||
tmp['node_health_check'] = args['node_health_check'] |
||||
cfg[row] = tmp |
||||
writeConf(cfg) |
||||
|
||||
makeLoadBalanceAllCfg(row) |
||||
mw.restartWeb() |
||||
return mw.returnJson(True, '修改成功', data) |
||||
|
||||
|
||||
def loadBalanceList(): |
||||
cfg = getConf() |
||||
return mw.returnJson(True, 'ok', cfg) |
||||
|
||||
|
||||
def loadBalanceDelete(): |
||||
args = getArgs() |
||||
data = checkArgs(args, ['row']) |
||||
if not data[0]: |
||||
return data[1] |
||||
|
||||
row = int(args['row']) |
||||
|
||||
cfg = getConf() |
||||
data = cfg[row] |
||||
|
||||
import site_api |
||||
sobj = site_api.site_api() |
||||
|
||||
sid = mw.M('sites').where('name=?', (data['domain'],)).getField('id') |
||||
|
||||
if type(sid) == list: |
||||
del(cfg[row]) |
||||
writeConf(cfg) |
||||
return mw.returnJson(False, '已经删除了!') |
||||
|
||||
status = sobj.delete(sid, data['domain'], 1) |
||||
status_data = json.loads(status) |
||||
|
||||
if status_data['status']: |
||||
del(cfg[row]) |
||||
writeConf(cfg) |
||||
|
||||
upstream_dir = mw.getServerDir() + '/web_conf/nginx/upstream' |
||||
rewrite_dir = mw.getServerDir() + '/web_conf/nginx/rewrite' |
||||
|
||||
upstream_file = upstream_dir + '/' + data['upstream_name'] + '.conf' |
||||
if os.path.exists(upstream_file): |
||||
os.remove(upstream_file) |
||||
|
||||
rewrite_file = rewrite_dir + '/' + data['domain'] + '.conf' |
||||
if os.path.exists(rewrite_file): |
||||
mw.writeFile(rewrite_file, '') |
||||
|
||||
return mw.returnJson(status_data['status'], status_data['msg']) |
||||
|
||||
|
||||
def http_get(url): |
||||
ret = re.search(r'https://', url) |
||||
if ret: |
||||
try: |
||||
from gevent import monkey |
||||
monkey.patch_ssl() |
||||
import requests |
||||
ret = requests.get(url=str(url), verify=False, timeout=10) |
||||
status = [200, 301, 302, 404, 403] |
||||
if ret.status_code in status: |
||||
return True |
||||
else: |
||||
return False |
||||
except: |
||||
return False |
||||
else: |
||||
try: |
||||
if sys.version_info[0] == 2: |
||||
import urllib2 |
||||
rec = urllib2.urlopen(url, timeout=3) |
||||
else: |
||||
import urllib.request |
||||
rec = urllib.request.urlopen(url, timeout=3) |
||||
status = [200, 301, 302, 404, 403] |
||||
if rec.getcode() in status: |
||||
return True |
||||
return False |
||||
except: |
||||
return False |
||||
|
||||
|
||||
def checkUrl(): |
||||
args = getArgs() |
||||
data = checkArgs(args, ['ip', 'port', 'path']) |
||||
if not data[0]: |
||||
return data[1] |
||||
|
||||
ip = args['ip'] |
||||
port = args['port'] |
||||
path = args['path'] |
||||
|
||||
if port == '443': |
||||
url = 'https://' + str(ip) + ':' + str(port) + str(path.strip()) |
||||
else: |
||||
url = 'http://' + str(ip) + ':' + str(port) + str(path.strip()) |
||||
ret = http_get(url) |
||||
if not ret: |
||||
return mw.returnJson(False, '访问节点[%s]失败' % url) |
||||
return mw.returnJson(True, '访问节点[%s]成功' % url) |
||||
|
||||
|
||||
def getHealthStatus(): |
||||
args = getArgs() |
||||
data = checkArgs(args, ['row']) |
||||
if not data[0]: |
||||
return data[1] |
||||
|
||||
row = int(args['row']) |
||||
|
||||
cfg = getConf() |
||||
data = cfg[row] |
||||
|
||||
url = 'http://' + data['domain'] + \ |
||||
'/upstream_status_' + data['upstream_name'] |
||||
|
||||
url_data = mw.httpGet(url) |
||||
return mw.returnJson(True, 'ok', json.loads(url_data)) |
||||
|
||||
|
||||
def getLogs(): |
||||
args = getArgs() |
||||
data = checkArgs(args, ['domain']) |
||||
if not data[0]: |
||||
return data[1] |
||||
|
||||
domain = args['domain'] |
||||
logs = mw.getLogsDir() + '/' + domain + '.log' |
||||
return logs |
||||
|
||||
if __name__ == "__main__": |
||||
func = sys.argv[1] |
||||
if func == 'status': |
||||
print(status()) |
||||
elif func == 'start': |
||||
print(start()) |
||||
elif func == 'stop': |
||||
print(stop()) |
||||
elif func == 'restart': |
||||
print(restart()) |
||||
elif func == 'reload': |
||||
print(reload()) |
||||
elif func == 'install_pre_inspection': |
||||
print(installPreInspection()) |
||||
elif func == 'add_load_balance': |
||||
print(addLoadBalance()) |
||||
elif func == 'load_balance_list': |
||||
print(loadBalanceList()) |
||||
elif func == 'load_balance_delete': |
||||
print(loadBalanceDelete()) |
||||
elif func == 'check_url': |
||||
print(checkUrl()) |
||||
elif func == 'get_logs': |
||||
print(getLogs()) |
||||
elif func == 'get_health_status': |
||||
print(getHealthStatus()) |
||||
else: |
||||
print('error') |
@ -0,0 +1,16 @@ |
||||
{ |
||||
"title":"OP负载均衡", |
||||
"tip":"soft", |
||||
"name":"op_load_balance", |
||||
"type":"其他插件", |
||||
"install_pre_inspection":true, |
||||
"ps":"基于OpenResty的负载均衡", |
||||
"shell":"install.sh", |
||||
"checks":"server/op_load_balance", |
||||
"path":"server/op_load_balance", |
||||
"author":"midoks", |
||||
"home":"https://github.com/midoks", |
||||
"date":"2023-02-02", |
||||
"pid": "1", |
||||
"versions": ["1.0"] |
||||
} |
@ -0,0 +1,45 @@ |
||||
#!/bin/bash |
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin |
||||
export PATH |
||||
|
||||
curPath=`pwd` |
||||
rootPath=$(dirname "$curPath") |
||||
rootPath=$(dirname "$rootPath") |
||||
serverPath=$(dirname "$rootPath") |
||||
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl |
||||
|
||||
action=$1 |
||||
version=$2 |
||||
sys_os=`uname` |
||||
|
||||
if [ -f ${rootPath}/bin/activate ];then |
||||
source ${rootPath}/bin/activate |
||||
fi |
||||
|
||||
if [ "$sys_os" == "Darwin" ];then |
||||
BAK='_bak' |
||||
else |
||||
BAK='' |
||||
fi |
||||
|
||||
Install_App(){ |
||||
echo '正在安装脚本文件...' > $install_tmp |
||||
mkdir -p $serverPath/op_load_balance |
||||
echo "${version}" > $serverPath/op_load_balance/version.pl |
||||
cd ${rootPath} && python3 ${rootPath}/plugins/op_load_balance/index.py start |
||||
echo 'install ok' > $install_tmp |
||||
} |
||||
|
||||
Uninstall_App(){ |
||||
cd ${rootPath} && python3 ${rootPath}/plugins/op_load_balance/index.py stop |
||||
rm -rf $serverPath/op_load_balance |
||||
} |
||||
|
||||
|
||||
action=$1 |
||||
if [ "${1}" == 'install' ];then |
||||
Install_App |
||||
else |
||||
Uninstall_App |
||||
fi |
@ -0,0 +1,606 @@ |
||||
function ooPost(method,args,callback){ |
||||
var _args = null;
|
||||
if (typeof(args) == 'string'){ |
||||
_args = JSON.stringify(toArrayObject(args)); |
||||
} else { |
||||
_args = JSON.stringify(args); |
||||
} |
||||
|
||||
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 }); |
||||
$.post('/plugins/run', {name:'op_load_balance', func:method, args:_args}, function(data) { |
||||
layer.close(loadT); |
||||
if (!data.status){ |
||||
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']}); |
||||
return; |
||||
} |
||||
|
||||
if(typeof(callback) == 'function'){ |
||||
callback(data); |
||||
} |
||||
},'json');
|
||||
} |
||||
|
||||
function ooAsyncPost(method,args){ |
||||
var _args = null;
|
||||
if (typeof(args) == 'string'){ |
||||
_args = JSON.stringify(toArrayObject(args)); |
||||
} else { |
||||
_args = JSON.stringify(args); |
||||
} |
||||
return syncPost('/plugins/run', {name:'op_load_balance', func:method, args:_args});
|
||||
} |
||||
|
||||
function ooPostCallbak(method, args, callback){ |
||||
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 }); |
||||
|
||||
var req_data = {}; |
||||
req_data['name'] = 'op_load_balance'; |
||||
req_data['func'] = method; |
||||
args['version'] = '1.0'; |
||||
|
||||
if (typeof(args) == 'string'){ |
||||
req_data['args'] = JSON.stringify(toArrayObject(args)); |
||||
} else { |
||||
req_data['args'] = JSON.stringify(args); |
||||
} |
||||
|
||||
$.post('/plugins/callback', req_data, function(data) { |
||||
layer.close(loadT); |
||||
if (!data.status){ |
||||
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']}); |
||||
return; |
||||
} |
||||
|
||||
if(typeof(callback) == 'function'){ |
||||
callback(data); |
||||
} |
||||
},'json');
|
||||
} |
||||
|
||||
function addNode(){ |
||||
layer.open({ |
||||
type: 1, |
||||
area: ['450px','580px'], |
||||
title: '添加节点', |
||||
closeBtn: 1, |
||||
shift: 5, |
||||
shadeClose: true, |
||||
btn:['提交','关闭'], |
||||
content: "<form class='bt-form pd20'>\ |
||||
<div class='line'>\ |
||||
<span class='tname'>IP地址</span>\ |
||||
<div class='info-r'>\ |
||||
<input name='ip' class='bt-input-text mr5' placeholder='负载名称,可以是英文字母和下划线,不能使用中文' type='text' style='width:250px' value='127.0.0.1'>\ |
||||
</div>\ |
||||
</div>\ |
||||
<div class='line'>\ |
||||
<span class='tname'>端口</span>\ |
||||
<div class='info-r'>\ |
||||
<input name='port' class='bt-input-text mr5' type='text' style='width:250px' value='80'>\ |
||||
</div>\ |
||||
</div>\ |
||||
<div class='line'>\ |
||||
<span class='tname'>验证文件路径</span>\ |
||||
<div class='info-r'>\ |
||||
<input name='path' class='bt-input-text mr5' type='text' style='width:250px' value='/'>\ |
||||
</div>\ |
||||
</div>\ |
||||
<div class='line'>\ |
||||
<span class='tname'>节点状态</span>\ |
||||
<div class='info-r'>\ |
||||
<select name='state'>\ |
||||
<option value='1'>参与者</option>\ |
||||
<option value='2'>备份</option>\ |
||||
<option value='0'>停用</option>\ |
||||
</select>\ |
||||
</div>\ |
||||
</div>\ |
||||
<div class='line'>\ |
||||
<span class='tname'>权重</span>\ |
||||
<div class='info-r'>\ |
||||
<input name='weight' class='bt-input-text mr5' type='text' style='width:250px' value='1'>\ |
||||
</div>\ |
||||
</div>\ |
||||
<div class='line'>\ |
||||
<span class='tname'>阈值</span>\ |
||||
<div class='info-r'>\ |
||||
<input name='max_fails' class='bt-input-text mr5' type='text' style='width:250px' value='2'>次\ |
||||
</div>\ |
||||
</div>\ |
||||
<div class='line'>\ |
||||
<span class='tname'>恢复时间</span>\ |
||||
<div class='info-r'>\ |
||||
<input name='fail_timeout' class='bt-input-text mr5' type='text' style='width:250px' value='10'>秒\ |
||||
</div>\ |
||||
</div>\ |
||||
<ul style='margin-left:10px' class='help-info-text c7'>\ |
||||
<li>备份状态: 指当其它节点都无法使用时才会使用此节点</li>\ |
||||
<li>参与状态: 正常参与负载均衡,请至少添加1个普通节点</li>\ |
||||
<li>验证文件路径: 用于检查文件路径地址是否可用</li>\ |
||||
<li>IP地址: 仅支持IP地址,否则无法正常参与负载均衡</li>\ |
||||
<li>阈值: 在恢复时间的时间段内,如果OpenResty与节点通信尝试失败的次数达到此值,OpenResty就认为服务器不可用</li>\ |
||||
</ul>\ |
||||
</form>", |
||||
success:function(){ |
||||
}, |
||||
yes:function(index) { |
||||
|
||||
var ip = $('input[name="ip"]').val(); |
||||
var port = $('input[name="port"]').val(); |
||||
var path = $('input[name="path"]').val(); |
||||
var state = $('select[name="state"]').val(); |
||||
var weight = $('input[name="weight"]').val(); |
||||
var max_fails = $('input[name="max_fails"]').val(); |
||||
var fail_timeout = $('input[name="fail_timeout"]').val(); |
||||
|
||||
ooPost('check_url', {ip:ip,port:port,path:path},function(rdata){
|
||||
var rdata = $.parseJSON(rdata.data); |
||||
showMsg(rdata.msg, function(){ |
||||
if (rdata.status){ |
||||
layer.close(index); |
||||
$('#nodecon .nulltr').hide(); |
||||
|
||||
var tbody = '<tr>'; |
||||
tbody +='<td>'+ip+'</td>'; |
||||
tbody +='<td>'+port+'</td>'; |
||||
tbody +='<td>'+path+'</td>'; |
||||
|
||||
tbody +="<td><select name='state'>"; |
||||
var state_option_list = { |
||||
'1':'参与者', |
||||
'2':'备份', |
||||
'0':'停用', |
||||
} |
||||
for (i in state_option_list) { |
||||
if (i == state){ |
||||
tbody +="<option value='"+i+"' selected>"+state_option_list[i]+"</option>"; |
||||
} else{ |
||||
tbody +="<option value='"+i+"'>"+state_option_list[i]+"</option>"; |
||||
} |
||||
} |
||||
tbody +="</select></td>"; |
||||
|
||||
tbody +='<td><input type="number" name="weight" value="'+weight+'" style="width:50px"></td>'; |
||||
tbody +='<td><input type="number" name="max_fails" value="'+max_fails+'" style="width:50px"></td>'; |
||||
tbody +='<td><input type="number" name="fail_timeout" value="'+fail_timeout+'" style="width:50px"></td>'; |
||||
tbody +='<td class="text-right" width="50"><a class="btlink minus delete">删除</a></td>'; |
||||
tbody += '</tr>'; |
||||
$('#nodecon').append(tbody); |
||||
|
||||
$('#nodecon .delete').click(function(){ |
||||
$(this).parent().parent().remove(); |
||||
if ($('#nodecon tr').length == 1 ){ |
||||
$('#nodecon .nulltr').show(); |
||||
} |
||||
}); |
||||
} |
||||
},{ icon: rdata.status ? 1 : 2 }, 2000); |
||||
}); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
function addBalance(){ |
||||
layer.open({ |
||||
type: 1, |
||||
area: ['750px','460px'], |
||||
title: '创建负载', |
||||
closeBtn: 1, |
||||
shift: 5, |
||||
shadeClose: true, |
||||
btn:['提交','关闭'], |
||||
content: "<form class='bt-form pd20'>\ |
||||
<div class='line'>\ |
||||
<span class='tname'>域名</span>\ |
||||
<div class='info-r'><textarea name='load_domain' class='bt-input-text mr5' placeholder='' style='width:95%;resize: none;height:90px;line-height:20px;'></textarea></div>\ |
||||
</div>\ |
||||
<div class='line'>\ |
||||
<span class='tname'>负载名称</span>\ |
||||
<div class='info-r'>\ |
||||
<input name='upstream_name' class='bt-input-text mr5' placeholder='负载名称,可以是英文字母和下划线,不能使用中文' type='text' style='width:95%' value=''>\ |
||||
</div>\ |
||||
</div>\ |
||||
<div class='line'>\ |
||||
<span class='tname'>节点调度</span>\ |
||||
<div class='info-r'>\ |
||||
<select name='node_algo'>\ |
||||
<option value='polling'>轮询[默认]</option>\ |
||||
<option value='ip_hash'>ip_hash</option>\ |
||||
<option value='fair'>fair</option>\ |
||||
<option value='url_hash'>url_hash</option>\ |
||||
<option value='least_conn'>least_conn</option>\ |
||||
</select>\ |
||||
</div>\ |
||||
</div>\ |
||||
<div class='line'>\ |
||||
<span class='tname'>节点健康检查</span>\ |
||||
<div class='info-r'>\ |
||||
<input type='checkbox' name='node_health_check' checked>\ |
||||
</div>\ |
||||
</div>\ |
||||
<div class='line'>\ |
||||
<span class='tname'>节点</span>\ |
||||
<div class='info-r'>\ |
||||
<div class='table-con divtable' style='max-height:120px;overflow:auto; margin-bottom:8px;width:95%'>\ |
||||
<table class='table table-hover' id='fixTable3'>\ |
||||
<thead>\ |
||||
<tr>\ |
||||
<th width='120'>IP地址</th>\ |
||||
<th width='60'>端口</th>\ |
||||
<th width='120'>验证路径</th>\ |
||||
<th width='60'>状态</th>\ |
||||
<th width='60'>权重</th>\ |
||||
<th width='60'>阀值</th>\ |
||||
<th width='120'>恢复时间</th>\ |
||||
<th width='80' class='text-right'>操作</th>\ |
||||
</tr>\ |
||||
</thead>\ |
||||
<tbody id='nodecon'>\ |
||||
<tr class='nulltr'>\ |
||||
<td colspan='8' align='center'>当前节点为空,请至少添加一个普通节点</td>\ |
||||
</tr>\ |
||||
</tbody>\ |
||||
</table>\ |
||||
</div>\ |
||||
<span class='btn btn-success btn-sm add_node' style='vertical-align:0'>添加节点</span>\ |
||||
</div>\ |
||||
</div>\ |
||||
</form>", |
||||
success:function(){ |
||||
$('textarea[name="load_domain"]').attr('placeholder','每行填写一个域名,默认为80端口。\n泛解析添加方法 *.domain.com\n如另加端口格式为 www.domain.com:88'); |
||||
var rval = getRandomString(6); |
||||
$('input[name="upstream_name"]').val('load_balance_'+rval); |
||||
|
||||
$('.add_node').click(function(){ |
||||
addNode(); |
||||
}); |
||||
}, |
||||
yes:function(index) { |
||||
var data = {}; |
||||
|
||||
var upstream_name = $('input[name="upstream_name"]').val(); |
||||
if (upstream_name == ''){ |
||||
layer.msg('负载名称不能为空!',{icon:0,time:2000,shade: [0.3, '#000']}); |
||||
return; |
||||
} |
||||
|
||||
var domain = $('textarea[name="load_domain"]').val().replace('http://','').replace('https://','').split("\n"); |
||||
if (domain[0] == ''){ |
||||
layer.msg('域名不能为空!',{icon:0,time:2000,shade: [0.3, '#000']}); |
||||
return; |
||||
} |
||||
|
||||
var domainlist = ''; |
||||
for(var i=1; i<domain.length; i++){ |
||||
domainlist += '"'+domain[i]+'",'; |
||||
} |
||||
domain ='{"domain":"'+domain[0]+'","domainlist":['+domainlist+'],"count":'+domain.length+'}';//拼接json
|
||||
data['domain'] = domain; |
||||
data['upstream_name'] = upstream_name; |
||||
|
||||
data['node_algo'] = $('select[name="node_algo"]').val(); |
||||
|
||||
data['node_health_check'] = 'fail'; |
||||
if ($('input[name="node_health_check"]').prop('checked')){ |
||||
data['node_health_check'] = 'ok'; |
||||
} |
||||
|
||||
var node_list = []; |
||||
$('#nodecon tr').each(function(){ |
||||
|
||||
var ip = $(this).find('td').eq(0).text(); |
||||
var port = $(this).find('td').eq(1).text(); |
||||
|
||||
if (port == ''){return;} |
||||
|
||||
var path = $(this).find('td').eq(2).text(); |
||||
var state = $(this).find('select[name="state"]').val(); |
||||
var weight = $(this).find('input[name="weight"]').val(); |
||||
var max_fails = $(this).find('input[name="max_fails"]').val(); |
||||
var fail_timeout = $(this).find('input[name="fail_timeout"]').val(); |
||||
|
||||
var tmp = { |
||||
ip:ip, |
||||
port:port, |
||||
path:path, |
||||
state:state, |
||||
weight:weight, |
||||
max_fails:max_fails, |
||||
fail_timeout:fail_timeout, |
||||
} |
||||
node_list.push(tmp); |
||||
}); |
||||
data['node_list'] = node_list; |
||||
ooPostCallbak('add_load_balance', data, function(rdata){ |
||||
var rdata = $.parseJSON(rdata.data); |
||||
showMsg(rdata.msg, function(){ |
||||
layer.close(index); |
||||
loadBalanceListRender(); |
||||
},{ icon: rdata.status ? 1 : 2 }, 2000); |
||||
}); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
function editBalance(data, row){ |
||||
layer.open({ |
||||
type: 1, |
||||
area: ['750px','400px'], |
||||
title: '编辑负载', |
||||
closeBtn: 1, |
||||
shift: 5, |
||||
shadeClose: true, |
||||
btn:['提交','关闭'], |
||||
content: "<form class='bt-form pd20'>\ |
||||
<div class='line'>\ |
||||
<span class='tname'>负载名称</span>\ |
||||
<div class='info-r'><input name='upstream_name' class='bt-input-text mr5' type='text' style='width:95%;background: rgb(238, 238, 238);' value='' readonly></div>\ |
||||
</div>\ |
||||
<div class='line'>\ |
||||
<span class='tname'>节点调度</span>\ |
||||
<div class='info-r'>\ |
||||
<select name='node_algo'>\ |
||||
<option value='polling'>轮询[默认]</option>\ |
||||
<option value='ip_hash'>ip_hash</option>\ |
||||
<option value='fair'>fair</option>\ |
||||
<option value='url_hash'>url_hash</option>\ |
||||
<option value='least_conn'>least_conn</option>\ |
||||
</select>\ |
||||
</div>\ |
||||
</div>\ |
||||
<div class='line'>\ |
||||
<span class='tname'>节点健康检查</span>\ |
||||
<div class='info-r'>\ |
||||
<input type='checkbox' name='node_health_check'>\ |
||||
</div>\ |
||||
</div>\ |
||||
<div class='line'>\ |
||||
<span class='tname'>节点</span>\ |
||||
<div class='info-r'>\ |
||||
<div class='table-con divtable' style='max-height:120px;overflow:auto; margin-bottom:8px;width:95%'>\ |
||||
<table class='table table-hover' id='fixTable3'>\ |
||||
<thead>\ |
||||
<tr>\ |
||||
<th width='120'>IP地址</th>\ |
||||
<th width='60'>端口</th>\ |
||||
<th width='120'>验证路径</th>\ |
||||
<th width='60'>状态</th>\ |
||||
<th width='60'>权重</th>\ |
||||
<th width='60'>阀值</th>\ |
||||
<th width='120'>恢复时间</th>\ |
||||
<th width='80' class='text-right'>操作</th>\ |
||||
</tr>\ |
||||
</thead>\ |
||||
<tbody id='nodecon'>\ |
||||
<tr class='nulltr'>\ |
||||
<td colspan='8' align='center'>当前节点为空,请至少添加一个普通节点</td>\ |
||||
</tr>\ |
||||
</tbody>\ |
||||
</table>\ |
||||
</div>\ |
||||
<span class='btn btn-success btn-sm add_node' style='vertical-align:0'>添加节点</span>\ |
||||
</div>\ |
||||
</div>\ |
||||
</form>", |
||||
success:function(){ |
||||
$('input[name="upstream_name"]').val(data['upstream_name']); |
||||
$('select[name="node_algo"]').val(data['node_algo']); |
||||
|
||||
$('input[name="node_health_check"]').prop('checked',false); |
||||
if (data['node_health_check'] == 'ok'){ |
||||
$('input[name="node_health_check"]').prop('checked',true); |
||||
} |
||||
|
||||
var node_list = data['node_list']; |
||||
if (node_list.length>0){ |
||||
$('#nodecon .nulltr').hide(); |
||||
} |
||||
|
||||
var state_option_list = { |
||||
'1':'参与者', |
||||
'2':'备份', |
||||
'0':'停用', |
||||
} |
||||
|
||||
for (var n in node_list) { |
||||
|
||||
var tbody = '<tr>'; |
||||
tbody +='<td>'+node_list[n]['ip']+'</td>'; |
||||
tbody +='<td>'+node_list[n]['port']+'</td>'; |
||||
tbody +='<td>'+node_list[n]['path']+'</td>'; |
||||
|
||||
tbody +="<td><select name='state'>"; |
||||
|
||||
for (i in state_option_list) { |
||||
if (i == node_list[n]['state']){ |
||||
tbody +="<option value='"+i+"' selected>"+state_option_list[i]+"</option>"; |
||||
} else{ |
||||
tbody +="<option value='"+i+"'>"+state_option_list[i]+"</option>"; |
||||
} |
||||
} |
||||
tbody +="</select></td>"; |
||||
|
||||
tbody +='<td><input type="number" name="weight" value="'+node_list[n]['weight']+'" style="width:50px"></td>'; |
||||
tbody +='<td><input type="number" name="max_fails" value="'+node_list[n]['max_fails']+'" style="width:50px"></td>'; |
||||
tbody +='<td><input type="number" name="fail_timeout" value="'+node_list[n]['fail_timeout']+'" style="width:50px"></td>'; |
||||
tbody +='<td class="text-right" width="50"><a class="btlink minus delete">删除</a></td>'; |
||||
tbody += '</tr>'; |
||||
$('#nodecon').append(tbody); |
||||
} |
||||
|
||||
$('#nodecon .delete').click(function(){ |
||||
$(this).parent().parent().remove(); |
||||
if ($('#nodecon tr').length == 1 ){ |
||||
$('#nodecon .nulltr').show(); |
||||
} |
||||
}); |
||||
|
||||
$('.add_node').click(function(){ |
||||
addNode(); |
||||
}); |
||||
}, |
||||
yes:function(index) { |
||||
var data = {}; |
||||
|
||||
data['node_algo'] = $('select[name="node_algo"]').val(); |
||||
data['node_health_check'] = 'fail'; |
||||
if ($('input[name="node_health_check"]').prop('checked')){ |
||||
data['node_health_check'] = 'ok'; |
||||
} |
||||
|
||||
var node_list = []; |
||||
$('#nodecon tr').each(function(){ |
||||
|
||||
var ip = $(this).find('td').eq(0).text(); |
||||
var port = $(this).find('td').eq(1).text(); |
||||
|
||||
if (port == ''){return;} |
||||
|
||||
var path = $(this).find('td').eq(2).text(); |
||||
var state = $(this).find('select[name="state"]').val(); |
||||
var weight = $(this).find('input[name="weight"]').val(); |
||||
var max_fails = $(this).find('input[name="max_fails"]').val(); |
||||
var fail_timeout = $(this).find('input[name="fail_timeout"]').val(); |
||||
|
||||
var tmp = { |
||||
ip:ip, |
||||
port:port, |
||||
path:path, |
||||
state:state, |
||||
weight:weight, |
||||
max_fails:max_fails, |
||||
fail_timeout:fail_timeout, |
||||
} |
||||
node_list.push(tmp); |
||||
}); |
||||
data['node_list'] = node_list; |
||||
data['row'] = row; |
||||
ooPostCallbak('edit_load_balance', data, function(rdata){ |
||||
var rdata = $.parseJSON(rdata.data); |
||||
showMsg(rdata.msg, function(){ |
||||
layer.close(index); |
||||
loadBalanceListRender(); |
||||
},{ icon: rdata.status ? 1 : 2 }, 2000); |
||||
}); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
function loadBalanceListRender(){ |
||||
ooPost('load_balance_list', {}, function(rdata){ |
||||
var rdata = $.parseJSON(rdata.data); |
||||
var alist = rdata.data; |
||||
|
||||
var tbody = ''; |
||||
for (var i = 0; i < alist.length; i++) { |
||||
tbody += '<tr>'; |
||||
tbody += '<td>'+alist[i]['domain']+'</td>'; |
||||
tbody += '<td>'+alist[i]['upstream_name']+'</td>'; |
||||
tbody += '<td>'+alist[i]['node_list'].length+'</td>'; |
||||
tbody += '<td><a class="btlink log_look" data-row="'+i+'">查看</a></td>'; |
||||
tbody += '<td><a class="btlink health_status" data-row="'+i+'">查看</a></td>'; |
||||
tbody += '<td style="text-align: right;"><a class="btlink edit" data-row="'+i+'">修改</a> | <a class="btlink delete" data-row="'+i+'">删除</a></td>'; |
||||
tbody += '</tr>'; |
||||
} |
||||
|
||||
$('#nodeTable').html(tbody); |
||||
$('.nodeTablePage .Pcount').text('共'+alist.length+'条'); |
||||
$('#nodeTable .edit').click(function(){ |
||||
var row = $(this).data('row'); |
||||
editBalance(alist[row],row); |
||||
}); |
||||
|
||||
$('#nodeTable .log_look').click(function(){ |
||||
var row = $(this).data('row'); |
||||
var args = {'domain':alist[row]['domain']}; |
||||
pluginRollingLogs('op_load_balance','','get_logs',JSON.stringify(args),20); |
||||
}); |
||||
|
||||
$('#nodeTable .health_status').click(function(){ |
||||
var row = $(this).data('row'); |
||||
ooPost('get_health_status', {row:row}, function(rdata){ |
||||
var rdata = $.parseJSON(rdata.data); |
||||
|
||||
var tval = ''; |
||||
for (var i = 0; i < rdata.data.length; i++) { |
||||
tval += '<tr>'; |
||||
tval += '<td>'+rdata.data[i]['name']+'</td>'; |
||||
|
||||
if (typeof(rdata.data[i]['down']) != 'undefined' && rdata.data[i]['down']){ |
||||
tval += '<td><span style="color:red;">不正常</span></td>'; |
||||
} else{ |
||||
tval += '<td><span class="btlink">正常</span></td>'; |
||||
} |
||||
tval += '</tr>'; |
||||
} |
||||
|
||||
var tbody = "<div class='bt-form pd20'>\ |
||||
<div>\ |
||||
<div id='gitea_table' class='divtable' style='margin-top:5px;'>\ |
||||
<table class='table table-hover'>\ |
||||
<thead>\ |
||||
<tr>\ |
||||
<th width='120'>地址</th>\ |
||||
<th width='60'>状态</th>\ |
||||
</tr>\ |
||||
</thead>\ |
||||
<tbody>"+tval+"</tbody>\ |
||||
</table>\ |
||||
</div>\ |
||||
</div>\ |
||||
</div>"; |
||||
|
||||
layer.open({ |
||||
type: 1, |
||||
area: ['500px','300px'], |
||||
title: '节点状态', |
||||
closeBtn: 1, |
||||
shift: 5, |
||||
shadeClose: true, |
||||
btn:['提交','关闭'], |
||||
content:tbody, |
||||
}); |
||||
}); |
||||
}); |
||||
|
||||
$('#nodeTable .delete').click(function(){ |
||||
var row = $(this).data('row'); |
||||
ooPost('load_balance_delete', {row:row}, function(rdata){ |
||||
var rdata = $.parseJSON(rdata.data); |
||||
showMsg(rdata.msg, function(){ |
||||
loadBalanceListRender(); |
||||
},{ icon: rdata.status ? 1 : 2 }, 2000); |
||||
}); |
||||
}); |
||||
|
||||
}); |
||||
} |
||||
|
||||
function loadBalanceList() { |
||||
var body = '<div class="bt-box active" style="display: block;">\ |
||||
<div class="mb10">\ |
||||
<button class="btn btn-success btn-sm" data-index="0" onclick="addBalance()">添加负载</button>\ |
||||
<div class="divtable mt10">\ |
||||
<table class="table table-hover">\ |
||||
<thead>\ |
||||
<tr>\ |
||||
<th>网站</th>\ |
||||
<th>负载名称</th>\ |
||||
<th>节点</th>\ |
||||
<th>日志</th>\ |
||||
<th>状态</th>\ |
||||
<th width="100" style="text-align: right;">操作</th>\ |
||||
</tr>\ |
||||
</thead>\ |
||||
<tbody id="nodeTable"></tbody>\ |
||||
</table>\ |
||||
<div class="nodeTablePage page" data-type="nodePage">\ |
||||
<div><span class="Pcount">共0条</span></div>\ |
||||
</div>\ |
||||
</div>\ |
||||
</div>\ |
||||
</div>\ |
||||
</div>'; |
||||
$(".soft-man-con").html(body); |
||||
loadBalanceListRender(); |
||||
} |
@ -0,0 +1,18 @@ |
||||
local hc = require "resty.upstream.healthcheck" |
||||
local ok, err = hc.spawn_checker { |
||||
shm = "healthcheck", |
||||
type = "http", |
||||
upstream = "{$UPSTREAM_NAME}", |
||||
http_req = "GET / HTTP/1.0\r\nHost: {$UPSTREAM_NAME}\r\n\r\n", |
||||
interval = 2000, |
||||
timeout = 6000, |
||||
fall = 3, |
||||
rise = 2, |
||||
valid_statuses = {200, 302}, |
||||
concurrency = 20, |
||||
} |
||||
|
||||
if not ok then |
||||
ngx.log(ngx.ERR, "=======> load balance health checker error: ", err) |
||||
return |
||||
end |
Loading…
Reference in new issue