update 2026-10-11 00:49:02
marry-jell / merge (push) Canceled after 0s

This commit is contained in:
action committed 2026-10-11 00:49:02 +08:00
1 parent 54d5be6086
commit 7ae707aaa6
8 files changed
+112 -64

No files matched your search

@@ -381,35 +381,36 @@ function connect_status()
local e = {} local e = {}
e.use_time = "" e.use_time = ""
local url = http.formvalue("url") local url = http.formvalue("url")
if not url or url == "" then
http_write_json(e)
return
end
local aliyun = string.find(url, "aliyun") local aliyun = string.find(url, "aliyun")
local chn_list = uci_get("@global[0]", "chn_list") or "direct" local chn_list = uci_get("@global[0]", "chn_list") or "direct"
local gfw_list = uci_get("@global[0]", "use_gfw_list") or "1" local gfw_list = uci_get("@global[0]", "use_gfw_list") or "1"
local proxy_mode = uci_get("@global[0]", "tcp_proxy_mode") or "proxy" local proxy_mode = uci_get("@global[0]", "tcp_proxy_mode") or "proxy"
local localhost_proxy = uci_get("@global[0]", "localhost_proxy") or "1" local localhost_proxy = uci_get("@global[0]", "localhost_proxy") or "1"
local socks_server = (localhost_proxy == "0") and api.get_cache_var("GLOBAL_SOCKS_server") or "" local socks_server = (localhost_proxy == "0") and api.get_cache_var("GLOBAL_SOCKS_server") or ""
url = "-w %{http_code}:%{time_pretransfer} " .. url local curl_args = "-w '%{http_code}:%{time_pretransfer}:%{time_starttransfer}' " .. util.shellquote(url)
if socks_server and socks_server ~= "" then if socks_server and socks_server ~= "" then
if (chn_list == "proxy" and gfw_list == "0" and proxy_mode ~= "proxy" and aliyun ~= nil) or (chn_list == "0" and gfw_list == "0" and proxy_mode == "proxy") then if (chn_list == "proxy" and gfw_list == "0" and proxy_mode ~= "proxy" and aliyun ~= nil) or (chn_list == "0" and gfw_list == "0" and proxy_mode == "proxy") then
-- 中国列表+阿里 or 全局 -- 中国列表+阿里 or 全局
url = "-x socks5h://" .. socks_server .. " " .. url curl_args = "-x " .. util.shellquote("socks5h://" .. socks_server) .. " " .. curl_args
elseif aliyun == nil then elseif aliyun == nil then
-- 其他代理模式+阿里以外网站 -- 其他代理模式+阿里以外网站
url = "-x socks5h://" .. socks_server .. " " .. url curl_args = "-x " .. util.shellquote("socks5h://" .. socks_server) .. " " .. curl_args
end end
end end
local result = luci.sys.exec('/usr/bin/curl --connect-timeout 3 --max-time 5 -o /dev/null -I -sk ' .. url) local result = luci.sys.exec('curl_result=$(/usr/bin/curl --connect-timeout 3 --max-time 5 -o /dev/null -I -sk ' .. curl_args .. '); [ $? -eq 0 ] && printf "%s" "$curl_result"')
local code = tonumber(luci.sys.exec("echo -n '" .. result .. "' | awk -F ':' '{print $1}'") or "0") local code, pretransfer, starttransfer = result:match("^%s*(%d+):([%d%.]+):([%d%.]+)%s*$")
if code ~= 0 then code, pretransfer, starttransfer = tonumber(code), tonumber(pretransfer), tonumber(starttransfer)
local use_time_str = luci.sys.exec("echo -n '" .. result .. "' | awk -F ':' '{print $2}'") if code and code > 0 then e.http_code = code end
local use_time = tonumber(use_time_str) -- A completed HTTP response, including 4xx/5xx, confirms homepage connectivity.
if use_time then if code and code >= 200 and code < 600 and pretransfer and pretransfer >= 0 and starttransfer and starttransfer > 0 and starttransfer >= pretransfer then
if use_time_str:find("%.") then -- HTTP request latency excludes connection and TLS handshakes.
e.use_time = string.format("%.2f", use_time * 1000) e.use_time = string.format("%.2f", (starttransfer - pretransfer) * 1000)
else e.handshake_time = string.format("%.2f", pretransfer * 1000)
e.use_time = string.format("%.2f", use_time / 1000) e.ping_type = "curl"
end
e.ping_type = "curl"
end
end end
http_write_json(e) http_write_json(e)
end end
@@ -438,17 +439,13 @@ function urltest_node()
local e = {} local e = {}
e.index = index e.index = index
local result = luci.sys.exec("/usr/share/passwall/test.sh url_test_node " .. util.shellquote(id or "")) local result = luci.sys.exec("/usr/share/passwall/test.sh url_test_node " .. util.shellquote(id or ""))
local code = tonumber(luci.sys.exec("echo -n '" .. result .. "' | awk -F ':' '{print $1}'") or "0") local code, pretransfer, starttransfer = result:match("^%s*(%d+):([%d%.]+):([%d%.]+)%s*$")
if code ~= 0 then code, pretransfer, starttransfer = tonumber(code), tonumber(pretransfer), tonumber(starttransfer)
local use_time_str = luci.sys.exec("echo -n '" .. result .. "' | awk -F ':' '{print $2}'") if code and code > 0 then e.http_code = code end
local use_time = tonumber(use_time_str) if code and code >= 200 and code < 600 and pretransfer and pretransfer >= 0 and starttransfer and starttransfer > 0 and starttransfer >= pretransfer then
if use_time then -- Keep node test parsing independent from the homepage test.
if use_time_str:find("%.") then e.use_time = string.format("%.2f", (starttransfer - pretransfer) * 1000)
e.use_time = string.format("%.2f", use_time * 1000) e.handshake_time = string.format("%.2f", pretransfer * 1000)
else
e.use_time = string.format("%.2f", use_time / 1000)
end
end
end end
http_write_json(e) http_write_json(e)
end end
+1 -1
View File
@@ -169,7 +169,7 @@ function del_cache_var(key)
end end
function set_cache_var(key, val) function set_cache_var(key, val)
sys.call(string.format('. /usr/share/passwall/utils.sh ; set_cache_var "%s" "%s"', key, val)) sys.call(string.format('. /usr/share/passwall/utils.sh ; set_cache_var %s %s', util.shellquote(tostring(key)), util.shellquote(tostring(val))))
end end
function get_cache_var(key) function get_cache_var(key)
@@ -139,7 +139,7 @@ https://github.com/pure-css/pure/blob/master/LICENSE.md
</div> </div>
</div> </div>
</div> </div>
<div class="pure-u-1-4 check" onclick="check_connect('aliyun', 'https://www.aliyun.com')" title="<%:TLS handshake test, latency for reference only%>"> <div class="pure-u-1-4 check" onclick="check_connect('aliyun', 'https://www.aliyun.com')" title="<%:HTTP request latency, for reference only%>">
<div class="block pure-g"> <div class="block pure-g">
<div class="pure-u-1-3"> <div class="pure-u-1-3">
<div class="img-con"> <div class="img-con">
@@ -151,7 +151,7 @@ https://github.com/pure-css/pure/blob/master/LICENSE.md
</div> </div>
</div> </div>
</div> </div>
<div class="pure-u-1-4 check" onclick="check_connect('google', 'https://www.google.com/generate_204')" title="<%:TLS handshake test, latency for reference only%>"> <div class="pure-u-1-4 check" onclick="check_connect('google', 'https://www.google.com/generate_204')" title="<%:HTTP request latency, for reference only%>">
<div class="block pure-g"> <div class="block pure-g">
<div class="pure-u-1-3"> <div class="pure-u-1-3">
<div class="img-con"> <div class="img-con">
@@ -163,7 +163,7 @@ https://github.com/pure-css/pure/blob/master/LICENSE.md
</div> </div>
</div> </div>
</div> </div>
<div class="pure-u-1-4 check" onclick="check_connect('github', 'https://github.com')" title="<%:TLS handshake test, latency for reference only%>"> <div class="pure-u-1-4 check" onclick="check_connect('github', 'https://github.com')" title="<%:HTTP request latency, for reference only%>">
<div class="block pure-g"> <div class="block pure-g">
<div class="pure-u-1-3"> <div class="pure-u-1-3">
<div class="img-con"> <div class="img-con">
@@ -175,7 +175,7 @@ https://github.com/pure-css/pure/blob/master/LICENSE.md
</div> </div>
</div> </div>
</div> </div>
<div class="pure-u-1-4 check" onclick="check_connect('youtube', 'https://www.youtube.com')" title="<%:TLS handshake test, latency for reference only%>"> <div class="pure-u-1-4 check" onclick="check_connect('youtube', 'https://www.youtube.com/generate_204')" title="<%:HTTP request latency, for reference only%>">
<div class="block pure-g"> <div class="block pure-g">
<div class="pure-u-1-3"> <div class="pure-u-1-3">
<div class="img-con"> <div class="img-con">
@@ -246,6 +246,7 @@ https://github.com/pure-css/pure/blob/master/LICENSE.md
if (s) { if (s) {
var div = s.parentNode.parentNode.parentNode.parentNode; var div = s.parentNode.parentNode.parentNode.parentNode;
div.removeAttribute('onclick'); div.removeAttribute('onclick');
div.title = "<%:HTTP request latency, for reference only%>";
s.innerHTML = '<%:Check...%>'; s.innerHTML = '<%:Check...%>';
var sendDate = (new Date()).getTime(); var sendDate = (new Date()).getTime();
XHR.get('<%=api.url("connect_status")%>', { XHR.get('<%=api.url("connect_status")%>', {
@@ -263,6 +264,7 @@ https://github.com/pure-css/pure/blob/master/LICENSE.md
s.className="red"; s.className="red";
} }
s.innerHTML = use_time + " ms"; s.innerHTML = use_time + " ms";
div.title += "\n<%:Initial handshake time%>: " + rv.handshake_time + " ms";
} else if (rv.status) { } else if (rv.status) {
s.className="green"; s.className="green";
s.innerHTML = "<%:Working...%>"; s.innerHTML = "<%:Working...%>";
@@ -710,6 +710,7 @@ table td, .table .td {
function urltest_node(cbi_id, dom) { function urltest_node(cbi_id, dom) {
if (dom.dataset.busy == "1" || !cbi_id) return; if (dom.dataset.busy == "1" || !cbi_id) return;
dom.dataset.busy = "1"; dom.dataset.busy = "1";
dom.title = "<%:HTTP request latency, for reference only%>";
dom.style.color = ""; dom.style.color = "";
dom.innerText = "<%:Check...%>"; dom.innerText = "<%:Check...%>";
XHR.get('<%=api.url("urltest_node")%>', { XHR.get('<%=api.url("urltest_node")%>', {
@@ -720,7 +721,7 @@ table td, .table .td {
let text = "<%:Error%>"; let text = "<%:Error%>";
if (x && x.status == 200) { if (x && x.status == 200) {
if (result.use_time == null || result.use_time.trim() == "") { if (result.use_time == null || result.use_time.trim() == "") {
text = "<%:Timeout%>"; text = result.http_code >= 400 ? "HTTP " + result.http_code : "<%:Timeout%>";
} else { } else {
let use_time = parseInt(result.use_time); let use_time = parseInt(result.use_time);
if (use_time < 1000) if (use_time < 1000)
@@ -728,6 +729,7 @@ table td, .table .td {
else if (use_time < 2000) else if (use_time < 2000)
color = "#fb9a05"; color = "#fb9a05";
text = use_time + " ms"; text = use_time + " ms";
dom.title += "\n<%:Initial handshake time%>: " + result.handshake_time + " ms";
} }
} }
dom.innerText = text; dom.innerText = text;
@@ -1417,7 +1419,7 @@ table td, .table .td {
innerHTML = innerHTML.split("{{tcping}}").join('<span class="tcping_value" cbiid="{{id}}"><a href="javascript:void(0)" style="color:inherit">---</a></span>'); innerHTML = innerHTML.split("{{tcping}}").join('<span class="tcping_value" cbiid="{{id}}"><a href="javascript:void(0)" style="color:inherit">---</a></span>');
} }
if (o["address"] && _port) { if (o["address"] && _port) {
innerHTML = innerHTML.split("{{url_test}}").join('<span class="ping"><a href="javascript:void(0)" onclick="javascript:urltest_node(\'{{id}}\', this)" title="<%:TLS handshake test, latency for reference only%>"><%:Test%></a></span>'); innerHTML = innerHTML.split("{{url_test}}").join('<span class="ping"><a href="javascript:void(0)" onclick="javascript:urltest_node(\'{{id}}\', this)" title="<%:HTTP request latency, for reference only%>"><%:Test%></a></span>');
} else { } else {
innerHTML = innerHTML.split("{{url_test}}").join('<span class="ping" cbiid="{{id}}">---</span>'); innerHTML = innerHTML.split("{{url_test}}").join('<span class="ping" cbiid="{{id}}">---</span>');
} }
+5 -2
View File
@@ -22,8 +22,11 @@ msgstr "连接失败"
msgid "Touch Check" msgid "Touch Check"
msgstr "点我检测" msgstr "点我检测"
msgid "TLS handshake test, latency for reference only" msgid "HTTP request latency, for reference only"
msgstr "TLS握手测试,延时仅供参考" msgstr "HTTP 请求延迟,仅供参考"
msgid "Initial handshake time"
msgstr "首次握手耗时"
msgid "Kernel Unsupported" msgid "Kernel Unsupported"
msgstr "内核不支持" msgstr "内核不支持"
@@ -21,7 +21,7 @@ local haproxy_dns = "127.0.0.1"
local cpu_thread = sys.exec('echo -n $(cat /proc/cpuinfo | grep "processor" | wc -l)') or "1" local cpu_thread = sys.exec('echo -n $(cat /proc/cpuinfo | grep "processor" | wc -l)') or "1"
local health_check_type = api.uci_get_c("@global_haproxy[0]", "health_check_type") or "tcp" local health_check_type = api.uci_get_c("@global_haproxy[0]", "health_check_type") or "tcp"
local health_check_inter = api.uci_get_c("@global_haproxy[0]", "health_check_inter") or "20" local health_check_inter = api.uci_get_c("@global_haproxy[0]", "health_check_inter") or "60"
local balancingStrategy = api.uci_get_c("@global_haproxy[0]", "balancingStrategy") or "roundrobin" local balancingStrategy = api.uci_get_c("@global_haproxy[0]", "balancingStrategy") or "roundrobin"
local console_port = api.uci_get_c("@global_haproxy[0]", "console_port") or "1188" local console_port = api.uci_get_c("@global_haproxy[0]", "console_port") or "1188"
local bind_local = api.uci_get_c("@global_haproxy[0]", "bind_local") or "0" local bind_local = api.uci_get_c("@global_haproxy[0]", "bind_local") or "0"
@@ -44,7 +44,7 @@ global
nbthread {{nbthread}} nbthread {{nbthread}}
external-check external-check
insecure-fork-wanted insecure-fork-wanted
spread-checks 50 spread-checks 20
tune.max-checks-per-thread 5 tune.max-checks-per-thread 5
defaults defaults
@@ -99,7 +99,7 @@ api.uci_foreach_c("haproxy_config", function(t)
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 = api.uci_get_c(lbss) local server_node = api.uci_get_c(lbss)
local hop = (health_check_type == "script_logic") and (server_node.hysteria_hop or server_node.hysteria2_hop) or nil local hop = (health_check_type == "script_logic") and server_node and (server_node.hysteria_hop or server_node.hysteria2_hop) or nil
hop = hop and hop:gsub(":", "-") or nil hop = hop and hop:gsub(":", "-") or nil
if server_node and server_node.address and (server_node.port or hop) then if server_node and server_node.address and (server_node.port or hop) then
server_remark = server_node.address .. ":" .. (server_node.port or hop) server_remark = server_node.address .. ":" .. (server_node.port or hop)
@@ -153,9 +153,12 @@ api.uci_foreach_c("haproxy_config", function(t)
end end
end) end)
local inter = tonumber((health_check_inter or "20"):match("^%d+")) local inter = tonumber(health_check_inter:match("^%d+")) or 60
inter = (inter and inter >= 20) and inter or 20 inter = math.max(inter, 20)
local inter_arg = "inter " .. inter .. "s fastinter " .. inter / 2 .. "s downinter " .. inter * 1.5 .. "s" -- 限制过渡状态的确认间隔,避免正常检测间隔较长时摘除或恢复过慢。
local fastinter = math.max(10, math.min(15, math.floor(inter / 2)))
local downinter = math.ceil(inter * 1.5)
local inter_arg = string.format("inter %ds fastinter %ds downinter %ds", inter, fastinter, downinter)
local sortTable = {} local sortTable = {}
for i in pairs(listens) do for i in pairs(listens) do
@@ -165,7 +168,28 @@ for i in pairs(listens) do
end end
table.sort(sortTable, function(a,b) return (a < b) end) table.sort(sortTable, function(a,b) return (a < b) end)
for i, port in pairs(sortTable) do local function server_endpoint(o)
local address = o.server_address:gsub("^%[(.*)%]$", "%1")
if address:find(":", 1, true) then address = "[" .. address .. "]" end
return address .. ":" .. o.server_port
end
local check_counts = {}
if health_check_type == "script_logic" then
for _, port in ipairs(sortTable) do
for _, o in ipairs(listens[port]) do
-- 域名可能解析到不同 IP,仅对相同的实际代理端点共享检测。
if api.is_ip(o.server_address) then
local endpoint = server_endpoint(o)
check_counts[endpoint] = (check_counts[endpoint] or 0) + 1
end
end
end
end
local shared_checks = {}
local shared_check_names = {}
for i, port in ipairs(sortTable) do
log(" + 入口 %s:%s" % {bind_address, port}) log(" + 入口 %s:%s" % {bind_address, port})
f_out:write("\n" .. string.format([[ f_out:write("\n" .. string.format([[
@@ -184,7 +208,7 @@ listen %s
local count_M, count_B = 1, 1 local count_M, count_B = 1, 1
for i, o in ipairs(listens[port]) do for i, o in ipairs(listens[port]) do
local remark = o.server_remark or "" local remark = (o.server_remark or ""):gsub("[%[%]]", "")
-- 防止重名导致无法运行 -- 防止重名导致无法运行
if tostring(o.backup) ~= "1" then if tostring(o.backup) ~= "1" then
remark = "M" .. count_M .. "-" .. remark remark = "M" .. count_M .. "-" .. remark
@@ -193,8 +217,18 @@ listen %s
remark = "B" .. count_B .. "-" .. remark remark = "B" .. count_B .. "-" .. remark
count_B = count_B + 1 count_B = count_B + 1
end end
local server = o.server_address .. ":" .. o.server_port local server = server_endpoint(o)
local server_conf = "server {{remark}} {{server}} weight {{weight}} {{resolvers}} check {{inter_arg}} rise 2 fall 2 {{backup}}" local check_arg = "check " .. inter_arg .. " rise 2 fall 2"
if (check_counts[server] or 0) > 1 then
local name = shared_check_names[server]
if not name then
name = "check_" .. (#shared_checks + 1)
shared_check_names[server] = name
table.insert(shared_checks, {name = name, server = server})
end
check_arg = "track " .. appname .. "_health_checks/" .. name
end
local server_conf = "server {{remark}} {{server}} weight {{weight}} {{resolvers}} {{check_arg}} {{backup}}"
server_conf = server_conf:gsub("{{remark}}", remark) server_conf = server_conf:gsub("{{remark}}", remark)
server_conf = server_conf:gsub("{{server}}", server) server_conf = server_conf:gsub("{{server}}", server)
server_conf = server_conf:gsub("{{weight}}", o.lbweight) server_conf = server_conf:gsub("{{weight}}", o.lbweight)
@@ -203,7 +237,7 @@ listen %s
resolvers = "" resolvers = ""
end end
server_conf = server_conf:gsub("{{resolvers}}", resolvers) server_conf = server_conf:gsub("{{resolvers}}", resolvers)
server_conf = server_conf:gsub("{{inter_arg}}", inter_arg) server_conf = server_conf:gsub("{{check_arg}}", check_arg)
server_conf = server_conf:gsub("{{backup}}", tostring(o.backup) == "1" and "backup" or "") server_conf = server_conf:gsub("{{backup}}", tostring(o.backup) == "1" and "backup" or "")
f_out:write(" " .. api.trim(server_conf) .. "\n") f_out:write(" " .. api.trim(server_conf) .. "\n")
@@ -216,6 +250,20 @@ listen %s
end end
end end
-- 独立检测 backend,避免入口服务器的手动维护状态传播到其他入口。
if #shared_checks > 0 then
f_out:write(string.format([[
backend %s_health_checks
mode tcp
option external-check
external-check command "/usr/share/%s/haproxy_check.sh"
]], appname, appname))
for _, check in ipairs(shared_checks) do
f_out:write(string.format("\tserver %s %s check %s rise 2 fall 2\n", check.name, check.server, inter_arg))
end
end
--控制台配置 --控制台配置
local console_user = api.uci_get_c("@global_haproxy[0]", "console_user") local console_user = api.uci_get_c("@global_haproxy[0]", "console_user")
local console_password = api.uci_get_c("@global_haproxy[0]", "console_password") local console_password = api.uci_get_c("@global_haproxy[0]", "console_password")
@@ -234,8 +282,7 @@ f_out:close()
--passwall内置健康检查URL --passwall内置健康检查URL
if health_check_type == "script_logic" then if health_check_type == "script_logic" then
local probeUrl = api.uci_get_c("@global_haproxy[0]", "health_probe_url") or "https://www.google.com/generate_204" local probeUrl = api.trim(api.uci_get_c("@global_haproxy[0]", "health_probe_url") or "")
local f_url = io.open(haproxy_path .. "/Probe_URL", "w") if probeUrl == "" then probeUrl = "https://www.google.com/generate_204" end
f_url:write(probeUrl) api.set_cache_var("HAPROXY_PROBE_URL", probeUrl)
f_url:close()
end end
@@ -1,7 +1,7 @@
#!/bin/sh #!/bin/sh
export PATH=/usr/sbin:/usr/bin:/sbin:/bin:/root/bin export PATH=/usr/sbin:/usr/bin:/sbin:/bin:/root/bin
CONFIG=passwall . /usr/share/passwall/utils.sh
listen_address=$1 listen_address=$1
listen_port=$2 listen_port=$2
@@ -13,19 +13,16 @@ busybox pgrep -af "${CONFIG}/" | grep -E 'app\.sh.*(start|stop)|nftables\.sh|ipt
exit 0 exit 0
} }
probe_file="/tmp/etc/passwall/haproxy/Probe_URL" probeUrl=$(get_cache_var "HAPROXY_PROBE_URL")
probeUrl="https://www.google.com/generate_204" probeUrl="${probeUrl:-https://www.google.com/generate_204}"
if [ -f "$probe_file" ]; then
firstLine=$(head -n 1 "$probe_file" | tr -d ' \t\n')
[ -n "$firstLine" ] && probeUrl="$firstLine"
fi
extra_params="-x socks5h://${server_address}:${server_port}" case "$server_address" in
if /usr/bin/curl --help all | grep -q "\-\-retry-all-errors"; then \[*\]) ;;
extra_params="${extra_params} --retry-all-errors" *:*) server_address="[$server_address]" ;;
fi esac
status=$(/usr/bin/curl -I -o /dev/null -skL ${extra_params} --connect-timeout 3 --retry 1 --max-time 6 -w "%{http_code}" "${probeUrl}") # 每轮只探测一次,连续成功/失败由 HAProxy 的 rise/fall 判定。
status=$(/usr/bin/curl -q -I -o /dev/null -sk --noproxy "" -x "socks5h://${server_address}:${server_port}" --connect-timeout 3 --max-time 6 -w "%{http_code}" "$probeUrl") || exit 1
case "$status" in case "$status" in
200|204) 200|204)
@@ -73,7 +73,7 @@ url_test_node() {
fi fi
sleep 2s sleep 2s
probeUrl=$(config_n_get @global_other[0] url_test_url https://www.google.com/generate_204) probeUrl=$(config_n_get @global_other[0] url_test_url https://www.google.com/generate_204)
result=$(curl --connect-timeout 3 --max-time 5 -o /dev/null -I -skL -w "%{http_code}:%{time_pretransfer}" "$@" -x "$curlx" "${probeUrl}") result=$(curl --connect-timeout 3 --max-time 5 -o /dev/null -I -sk -w "%{http_code}:%{time_pretransfer}:%{time_starttransfer}" "$@" -x "$curlx" "${probeUrl}") || result=0
# 结束 SS 插件进程 # 结束 SS 插件进程
if [ "$_type" != "socks" ]; then if [ "$_type" != "socks" ]; then
pid_file="${TMP_PATH}/${test_flag}_plugin.pid" pid_file="${TMP_PATH}/${test_flag}_plugin.pid"