luci: haproxy use logic implement accurate availability

So fragrant ~
This commit is contained in:
xiaorouji 2023-03-30 15:49:53 +08:00 committed by sbwml
parent c5e704b735
commit eadb44a03a
4 changed files with 108 additions and 11 deletions

View File

@ -45,11 +45,29 @@ o = s:option(Value, "console_port", translate("Console Port"), translate(
o.default = "1188" o.default = "1188"
o:depends("balancing_enable", true) o:depends("balancing_enable", true)
---- Health Check Type
o = s:option(ListValue, "health_check_type", translate("Health Check Type"))
o:value("tcp", "TCP")
o:value("passwall_logic", translate("Availability test") .. string.format("(passwall %s)", translate("Inner implement")))
o:depends("balancing_enable", true)
---- Health Check Inter
o = s:option(Value, "health_check_inter", translate("Health Check Inter"), translate("Units:seconds"))
o.default = "10"
o:depends("balancing_enable", true)
o = s:option(DummyValue, "health_check_tips", " ")
o.rawhtml = true
o.cfgvalue = function(t, n)
return string.format('<span style="color: red">%s</span>', translate("When the availability test is used, the load balancing node will be converted into a Socks node. when node list set customizing, must be a Socks node, otherwise the health check will be invalid."))
end
o:depends("health_check_type", "passwall_logic")
-- [[ Balancing Settings ]]-- -- [[ Balancing Settings ]]--
s = m:section(TypedSection, "haproxy_config", "", s = m:section(TypedSection, "haproxy_config", "",
"<font color='red'>" .. "<font color='red'>" ..
translate("Add a node, Export Of Multi WAN Only support Multi Wan. Load specific gravity range 1-256. Multiple primary servers can be load balanced, standby will only be enabled when the primary server is offline! Multiple groups can be set, Haproxy port same one for each group.") .. translate("Add a node, Export Of Multi WAN Only support Multi Wan. Load specific gravity range 1-256. Multiple primary servers can be load balanced, standby will only be enabled when the primary server is offline! Multiple groups can be set, Haproxy port same one for each group.") ..
"\n" .. translate("Note that the node configuration parameters for load balancing must be consistent, otherwise problems can arise!") .. "\n" .. translate("Note that the node configuration parameters for load balancing must be consistent when use TCP health check type, otherwise it cannot be used normally!") ..
"</font>") "</font>")
s.template = "cbi/tblsection" s.template = "cbi/tblsection"
s.sortable = true s.sortable = true

View File

@ -694,11 +694,23 @@ msgstr "在浏览器输入路由IP加端口访问192.168.1.1:1188"
msgid "Haproxy Port" msgid "Haproxy Port"
msgstr "负载均衡端口" msgstr "负载均衡端口"
msgid "Health Check Type"
msgstr "健康检查类型"
msgid "Inner implement"
msgstr "内置实现"
msgid "Health Check Inter"
msgstr "健康检查节点间隔时间"
msgid "When the availability test is used, the load balancing node will be converted into a Socks node. when node list set customizing, must be a Socks node, otherwise the health check will be invalid."
msgstr "当使用可用性测试时负载均衡节点将转换成Socks节点。下面的节点列表自定义时必须为Socks节点否则健康检查将无效。"
msgid "Add a node, Export Of Multi WAN Only support Multi Wan. Load specific gravity range 1-256. Multiple primary servers can be load balanced, standby will only be enabled when the primary server is offline! Multiple groups can be set, Haproxy port same one for each group." msgid "Add a node, Export Of Multi WAN Only support Multi Wan. Load specific gravity range 1-256. Multiple primary servers can be load balanced, standby will only be enabled when the primary server is offline! Multiple groups can be set, Haproxy port same one for each group."
msgstr "添加节点指定出口功能是为多WAN用户准备的。负载比重范围1-256。多个主服务器可以负载均衡备用只有在主服务器离线时才会启用可以设置多个组负载均衡端口相同则为一组。" msgstr "添加节点指定出口功能是为多WAN用户准备的。负载比重范围1-256。多个主服务器可以负载均衡备用只有在主服务器离线时才会启用可以设置多个组负载均衡端口相同则为一组。"
msgid "Note that the node configuration parameters for load balancing must be consistent, otherwise problems can arise!" msgid "Note that the node configuration parameters for load balancing must be consistent when use TCP health check type, otherwise it cannot be used normally!"
msgstr "注意,负载均衡的节点配置参数必须一致,否则会出问题!" msgstr "注意,当使用TCP健康检查时负载均衡的节点配置参数必须一致,否则无法正常使用"
msgid "Node" msgid "Node"
msgstr "节点" msgstr "节点"

View File

@ -17,10 +17,24 @@ function get_ip_port_from(str)
return result_ip, result_port return result_ip, result_port
end end
local new_port
local function get_new_port()
if new_port then
new_port = tonumber(sys.exec(string.format("echo -n $(/usr/share/%s/app.sh get_new_port %s tcp)", appname, new_port + 1)))
else
new_port = tonumber(sys.exec(string.format("echo -n $(/usr/share/%s/app.sh get_new_port auto tcp)", appname)))
end
return new_port
end
local var = api.get_args(arg) local var = api.get_args(arg)
local haproxy_path = var["-path"] local haproxy_path = var["-path"]
local haproxy_conf = var["-conf"] local haproxy_conf = var["-conf"]
local health_check_type = uci:get(appname, "@global_haproxy[0]", "health_check_type") or "tcp"
local health_check_inter = uci:get(appname, "@global_haproxy[0]", "health_check_inter") or "10"
health_check_inter = tonumber(health_check_inter) * 1000
log("HAPROXY 负载均衡...") log("HAPROXY 负载均衡...")
fs.mkdir(haproxy_path) fs.mkdir(haproxy_path)
local haproxy_file = haproxy_path .. "/" .. haproxy_conf local haproxy_file = haproxy_path .. "/" .. haproxy_conf
@ -30,9 +44,9 @@ local f_out = io.open(haproxy_file, "a")
local haproxy_config = [[ local haproxy_config = [[
global global
log 127.0.0.1 local2 log 127.0.0.1 local2
chroot %s
maxconn 60000 maxconn 60000
stats socket %s/haproxy.sock stats socket %s/haproxy.sock
%s
daemon daemon
defaults defaults
@ -57,31 +71,59 @@ resolvers mydns
nameserver dns1 127.0.0.1:53 nameserver dns1 127.0.0.1:53
resolve_retries 3 resolve_retries 3
timeout retry 3s timeout retry 3s
hold valid 10s hold valid 30s
]] ]]
f_out:write(string.format(haproxy_config, haproxy_path, haproxy_path)) f_out:write(string.format(haproxy_config, haproxy_path, health_check_type == "passwall_logic" and string.format([[
external-check
insecure-fork-wanted
]]) or ""
))
local listens = {} local listens = {}
uci:foreach(appname, "haproxy_config", function(t) uci:foreach(appname, "haproxy_config", function(t)
if t.enabled == "1" then if t.enabled == "1" then
local server_remark
local server_address local server_address
local server_port local server_port
local lbss = t.lbss local lbss = t.lbss
local listen_port = tonumber(t.haproxy_port) or 0 local listen_port = tonumber(t.haproxy_port) or 0
local server_node = uci:get_all(appname, lbss) local server_node = uci:get_all(appname, lbss)
if server_node and server_node.address and server_node.port then if server_node and server_node.address and server_node.port then
server_remark = server_node.address .. ":" .. server_node.port
server_address = server_node.address server_address = server_node.address
server_port = server_node.port server_port = server_node.port
if health_check_type == "passwall_logic" then
if server_node.type ~= "Socks" then
local relay_port = server_node.port
new_port = get_new_port()
local config_file = string.format("haproxy_%s_%s.json", t[".name"], new_port)
sys.call(string.format('/usr/share/%s/app.sh run_socks "%s"> /dev/null',
appname,
string.format("flag=%s node=%s bind=%s socks_port=%s config_file=%s",
new_port, --flag
server_node[".name"], --node
"127.0.0.1", --bind
new_port, --socks port
config_file --config file
)
)
)
server_address = "127.0.0.1"
server_port = new_port
end
end
else else
server_address, server_port = get_ip_port_from(lbss) server_address, server_port = get_ip_port_from(lbss)
server_remark = server_address .. ":" .. server_port
end end
if server_address and server_port and listen_port > 0 then if server_address and server_port and listen_port > 0 then
if not listens[listen_port] then if not listens[listen_port] then
listens[listen_port] = {} listens[listen_port] = {}
end end
t.server_remark = server_remark
t.server_address = server_address t.server_address = server_address
t.server_port = server_port t.server_port = server_port
table.insert(listens[listen_port], t) table.insert(listens[listen_port], t)
@ -109,12 +151,19 @@ listen %s
balance roundrobin balance roundrobin
]], port, port)) ]], port, port))
for i, o in ipairs(listens[port]) do if health_check_type == "passwall_logic" then
local server = o.server_address .. ":" .. o.server_port
local remark = server:gsub("%[", ""):gsub("%]", "")
f_out:write(string.format([[ f_out:write(string.format([[
server %s %s weight %s check resolvers mydns inter 1500 rise 1 fall 3 %s option external-check
]], remark, server, o.lbweight, o.backup == "1" and "backup" or "")) external-check command "/usr/share/passwall/haproxy_check.sh"
]], port, port))
end
for i, o in ipairs(listens[port]) do
local remark = o.server_remark
local server = o.server_address .. ":" .. o.server_port
f_out:write(string.format([[
server %s %s weight %s check resolvers mydns inter %s rise 1 fall 3 %s
]], remark, server, o.lbweight, health_check_inter, o.backup == "1" and "backup" or ""))
if o.export ~= "0" then if o.export ~= "0" then
sys.call(string.format("/usr/share/passwall/app.sh add_ip2route %s %s", o.server_address, o.export)) sys.call(string.format("/usr/share/passwall/app.sh add_ip2route %s %s", o.server_address, o.export))

View File

@ -0,0 +1,18 @@
#!/bin/sh
listen_address=$1
listen_port=$2
server_address=$3
server_port=$4
status=$(/usr/bin/curl -I -o /dev/null -skL -x socks5h://${server_address}:${server_port} --connect-timeout 3 --retry 3 -w %{http_code} "https://www.google.com/generate_204")
case "$status" in
204|\
200)
status=200
;;
esac
return_code=1
if [ "$status" = "200" ]; then
return_code=0
fi
exit ${return_code}