Files
EasyTier/script/test-cli-multi-instance.sh
KKRainbow e6ac31fb20 feat(web): add webhook-managed machine access and multi-instance CLI support (#1989)
* feat: add webhook-managed access and multi-instance CLI support
* fix(foreign): verify credential of foreign credential peer
2026-03-15 12:08:50 +08:00

270 lines
6.3 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
REPO_ROOT=$(CDPATH= cd -- "$SCRIPT_DIR/.." && pwd)
CORE_BIN=${CORE_BIN:-"$REPO_ROOT/target/debug/easytier-core"}
CLI_BIN=${CLI_BIN:-"$REPO_ROOT/target/debug/easytier-cli"}
TMPDIR_PATH=""
CORE_PID=""
PYTHON_BIN=${PYTHON_BIN:-python3}
print_section() {
printf '\n==> %s\n' "$1"
}
print_output() {
local title="$1"
local content="$2"
printf -- '---- %s ----\n' "$title"
printf '%s\n' "$content"
printf -- '---- end %s ----\n' "$title"
}
build_binaries() {
print_section "Building easytier-core and easytier-cli"
cargo build -p easytier --bin easytier-core --bin easytier-cli
}
ensure_binaries() {
if [[ "${SKIP_BUILD:-0}" != "1" ]] || [[ ! -x "$CORE_BIN" ]] || [[ ! -x "$CLI_BIN" ]]; then
build_binaries
fi
}
make_tmpdir() {
"$PYTHON_BIN" - <<'PY'
import tempfile
print(tempfile.mkdtemp(prefix="easytier-cli-e2e-"))
PY
}
cleanup_tmpdir() {
TMPDIR_TO_DELETE="$1" "$PYTHON_BIN" - <<'PY'
import os
import shutil
shutil.rmtree(os.environ["TMPDIR_TO_DELETE"], ignore_errors=True)
PY
}
alloc_port() {
"$PYTHON_BIN" - <<'PY'
import socket
sock = socket.socket()
sock.bind(("127.0.0.1", 0))
print(sock.getsockname()[1])
sock.close()
PY
}
wait_for_cli() {
local rpc_port="$1"
local attempts=0
while (( attempts < 50 )); do
if "$CLI_BIN" -p "127.0.0.1:${rpc_port}" -o json node >/dev/null 2>&1; then
return 0
fi
attempts=$((attempts + 1))
sleep 0.2
done
return 1
}
run_cmd() {
local __var_name="$1"
local title="$2"
shift 2
print_section "$title"
printf '+'
for arg in "$@"; do
printf ' %q' "$arg"
done
printf '\n'
local output
if ! output=$("$@" 2>&1); then
print_output "$title output" "$output"
return 1
fi
print_output "$title output" "$output"
printf -v "$__var_name" '%s' "$output"
}
assert_text_output() {
local text_output="$1"
grep -F '== e2e-inst-a (' <<<"$text_output" >/dev/null
grep -F '== e2e-inst-b (' <<<"$text_output" >/dev/null
}
assert_multi_instance_json() {
local json_payload="$1"
JSON_PAYLOAD="$json_payload" "$PYTHON_BIN" - <<'PY'
import json
import os
data = json.loads(os.environ["JSON_PAYLOAD"])
assert isinstance(data, list), data
assert len(data) == 2, data
names = {item["instance_name"] for item in data}
assert names == {"e2e-inst-a", "e2e-inst-b"}, names
for item in data:
assert item["instance_id"], item
assert isinstance(item["result"], dict), item
PY
}
assert_single_instance_json() {
local json_payload="$1"
JSON_PAYLOAD="$json_payload" "$PYTHON_BIN" - <<'PY'
import json
import os
data = json.loads(os.environ["JSON_PAYLOAD"])
assert isinstance(data, dict), data
assert data["config"].find('instance_name = "e2e-inst-a"') >= 0, data["config"]
PY
}
assert_whitelist_fanout() {
local json_payload="$1"
JSON_PAYLOAD="$json_payload" "$PYTHON_BIN" - <<'PY'
import json
import os
data = json.loads(os.environ["JSON_PAYLOAD"])
assert len(data) == 2, data
for item in data:
assert item["result"]["tcp_ports"] == ["80", "443"], item
assert item["result"]["udp_ports"] == [], item
PY
}
assert_single_instance_write() {
local json_payload="$1"
JSON_PAYLOAD="$json_payload" "$PYTHON_BIN" - <<'PY'
import json
import os
data = {item["instance_name"]: item["result"] for item in json.loads(os.environ["JSON_PAYLOAD"])}
assert data["e2e-inst-a"]["tcp_ports"] == ["80", "443"], data
assert data["e2e-inst-b"]["tcp_ports"] == [], data
PY
}
main() {
command -v "$PYTHON_BIN" >/dev/null 2>&1 || {
echo "python interpreter not found: $PYTHON_BIN" >&2
exit 1
}
ensure_binaries
TMPDIR_PATH=$(make_tmpdir)
print_section "Created temporary test directory"
printf '%s\n' "$TMPDIR_PATH"
local rpc_port
rpc_port=$(alloc_port)
print_section "Allocated RPC port"
printf '%s\n' "$rpc_port"
cleanup() {
if [[ -n "$CORE_PID" ]] && kill -0 "$CORE_PID" >/dev/null 2>&1; then
kill "$CORE_PID" >/dev/null 2>&1 || true
wait "$CORE_PID" >/dev/null 2>&1 || true
fi
if [[ -n "$TMPDIR_PATH" ]]; then
cleanup_tmpdir "$TMPDIR_PATH"
fi
}
trap cleanup EXIT
cat >"$TMPDIR_PATH/inst-a.toml" <<'EOF'
instance_name = "e2e-inst-a"
listeners = []
[network_identity]
network_name = "e2e-net-a"
network_secret = ""
[flags]
no_tun = true
enable_ipv6 = false
EOF
cat >"$TMPDIR_PATH/inst-b.toml" <<'EOF'
instance_name = "e2e-inst-b"
listeners = []
[network_identity]
network_name = "e2e-net-b"
network_secret = ""
[flags]
no_tun = true
enable_ipv6 = false
EOF
"$CORE_BIN" --config-dir "$TMPDIR_PATH" --rpc-portal "127.0.0.1:${rpc_port}" \
>"$TMPDIR_PATH/core.log" 2>&1 &
CORE_PID=$!
print_section "Started easytier-core"
printf 'pid=%s\n' "$CORE_PID"
wait_for_cli "$rpc_port"
print_output "easytier-core startup log" "$(cat "$TMPDIR_PATH/core.log")"
local text_output
run_cmd text_output \
"Case 1: node fanout in table mode" \
"$CLI_BIN" -p "127.0.0.1:${rpc_port}" node
assert_text_output "$text_output"
local json_output
run_cmd json_output \
"Case 2: node fanout in JSON mode" \
"$CLI_BIN" -p "127.0.0.1:${rpc_port}" -o json node
assert_multi_instance_json "$json_output"
local single_output
run_cmd single_output \
"Case 3: explicit instance selector stays single-instance" \
"$CLI_BIN" -p "127.0.0.1:${rpc_port}" --instance-name e2e-inst-a -o json node
assert_single_instance_json "$single_output"
local set_whitelist_output
run_cmd set_whitelist_output \
"Case 4: whitelist set-tcp fans out to all instances" \
"$CLI_BIN" -p "127.0.0.1:${rpc_port}" whitelist set-tcp 80,443
local whitelist_output
run_cmd whitelist_output \
"Case 5: whitelist show confirms fanout write" \
"$CLI_BIN" -p "127.0.0.1:${rpc_port}" -o json whitelist show
assert_whitelist_fanout "$whitelist_output"
local clear_whitelist_output
run_cmd clear_whitelist_output \
"Case 6: explicit selector write only touches one instance" \
"$CLI_BIN" -p "127.0.0.1:${rpc_port}" --instance-name e2e-inst-b whitelist clear-tcp
local cleared_output
run_cmd cleared_output \
"Case 7: whitelist show confirms single-instance write isolation" \
"$CLI_BIN" -p "127.0.0.1:${rpc_port}" -o json whitelist show
assert_single_instance_write "$cleared_output"
print_section "Result"
echo "CLI multi-instance E2E passed"
}
main "$@"