mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-05-06 17:59:11 +00:00
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
This commit is contained in:
Executable
+269
@@ -0,0 +1,269 @@
|
||||
#!/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 "$@"
|
||||
Reference in New Issue
Block a user