mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-04-22 16:17:23 +08:00
e6ac31fb20
* feat: add webhook-managed access and multi-instance CLI support * fix(foreign): verify credential of foreign credential peer
270 lines
6.3 KiB
Bash
Executable File
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 "$@"
|