test persist reload integration
This commit is contained in:
@@ -144,13 +144,14 @@ tests/run_all.sh --skip-integration
|
||||
- `tests/test_storage.sh`:规则存储
|
||||
- `tests/test_env_check.sh`:环境检查与修复
|
||||
- `tests/test_rules_unit.sh`:mock iptables 下的增删回滚
|
||||
- `tests/test_integration.sh`:真实 iptables 生命周期测试
|
||||
- `tests/test_integration.sh`:真实 iptables 生命周期 + save/reload 持久化回放测试
|
||||
|
||||
`tests/test_integration.sh` 的执行策略:
|
||||
|
||||
- root 环境下直接执行
|
||||
- 非 root 但支持 `unshare -Urn` 时,会进入隔离网络命名空间执行
|
||||
- 两者都不满足时会输出 `SKIP`
|
||||
- 持久化验证不会直接改写宿主 `/etc/iptables`,而是通过临时 `netfilter-persistent` 包装器把 `save/reload` 落到测试目录中的 `rules.v4` / `rules.v6`
|
||||
|
||||
## 手工验收建议
|
||||
|
||||
|
||||
51
tests/mocks/persist-fixture.sh
Executable file
51
tests/mocks/persist-fixture.sh
Executable file
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
: "${PERSIST_RULES_V4:?PERSIST_RULES_V4 is required}"
|
||||
: "${PERSIST_RULES_V6:=}"
|
||||
: "${IPTABLES_SAVE_BIN:=iptables-save}"
|
||||
: "${IP6TABLES_SAVE_BIN:=ip6tables-save}"
|
||||
: "${IPTABLES_RESTORE_BIN:=iptables-restore}"
|
||||
: "${IP6TABLES_RESTORE_BIN:=ip6tables-restore}"
|
||||
: "${PERSIST_FIXTURE_LOG:=}"
|
||||
|
||||
log_action() {
|
||||
[[ -n ${PERSIST_FIXTURE_LOG} ]] || return 0
|
||||
printf '%s %s\n' "$(basename -- "$0")" "$*" >>"${PERSIST_FIXTURE_LOG}"
|
||||
}
|
||||
|
||||
save_family_rules() {
|
||||
local save_bin=$1
|
||||
local output_file=$2
|
||||
[[ -n ${output_file} ]] || return 0
|
||||
mkdir -p "$(dirname -- "${output_file}")"
|
||||
if command -v "${save_bin}" >/dev/null 2>&1; then
|
||||
"${save_bin}" >"${output_file}"
|
||||
fi
|
||||
}
|
||||
|
||||
reload_family_rules() {
|
||||
local restore_bin=$1
|
||||
local input_file=$2
|
||||
[[ -n ${input_file} && -f ${input_file} ]] || return 0
|
||||
if command -v "${restore_bin}" >/dev/null 2>&1; then
|
||||
"${restore_bin}" <"${input_file}"
|
||||
fi
|
||||
}
|
||||
|
||||
case ${1-} in
|
||||
save)
|
||||
log_action "$@"
|
||||
save_family_rules "${IPTABLES_SAVE_BIN}" "${PERSIST_RULES_V4}"
|
||||
save_family_rules "${IP6TABLES_SAVE_BIN}" "${PERSIST_RULES_V6}"
|
||||
;;
|
||||
reload)
|
||||
log_action "$@"
|
||||
reload_family_rules "${IPTABLES_RESTORE_BIN}" "${PERSIST_RULES_V4}"
|
||||
reload_family_rules "${IP6TABLES_RESTORE_BIN}" "${PERSIST_RULES_V6}"
|
||||
;;
|
||||
*)
|
||||
printf 'usage: %s <save|reload>\n' "$(basename -- "$0")" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
@@ -41,17 +41,29 @@ if ! command -v iptables >/dev/null 2>&1; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if ! command -v iptables-save >/dev/null 2>&1 || ! command -v iptables-restore >/dev/null 2>&1; then
|
||||
printf 'SKIP: iptables-save/iptables-restore 不可用,跳过集成测试。\n'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
TMP_DIR=$(mktemp -d)
|
||||
BACKUP_V4="${TMP_DIR}/iptables.v4.bak"
|
||||
BACKUP_V6="${TMP_DIR}/iptables.v6.bak"
|
||||
PERSIST_RULES_V4="${TMP_DIR}/rules.v4"
|
||||
PERSIST_RULES_V6="${TMP_DIR}/rules.v6"
|
||||
PERSIST_FIXTURE_LOG="${TMP_DIR}/persist.log"
|
||||
|
||||
cleanup() {
|
||||
restore_runtime_from_backup() {
|
||||
if [[ -f ${BACKUP_V4} ]]; then
|
||||
iptables-restore <"${BACKUP_V4}" >/dev/null 2>&1 || true
|
||||
fi
|
||||
if [[ -f ${BACKUP_V6} ]]; then
|
||||
if [[ -f ${BACKUP_V6} ]] && command -v ip6tables-restore >/dev/null 2>&1; then
|
||||
ip6tables-restore <"${BACKUP_V6}" >/dev/null 2>&1 || true
|
||||
fi
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
restore_runtime_from_backup
|
||||
rm -rf "${TMP_DIR}"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
@@ -65,24 +77,50 @@ export IPF_STORAGE_DIR="${TMP_DIR}/storage"
|
||||
export IPF_STORAGE_DB="${IPF_STORAGE_DIR}/rules.db"
|
||||
export IPF_LOCK_FILE="${IPF_STORAGE_DIR}/.lock"
|
||||
export IPF_SKIP_ENV_CHECK=1
|
||||
export IPF_SKIP_PERSIST=1
|
||||
export IPF_FORCE_PLAIN_UI=1
|
||||
export NETFILTER_PERSISTENT_BIN="${ROOT_DIR}/tests/mocks/persist-fixture.sh"
|
||||
export PERSIST_RULES_V4
|
||||
export PERSIST_RULES_V6
|
||||
export PERSIST_FIXTURE_LOG
|
||||
|
||||
# shellcheck source=lib/common.sh
|
||||
source "${ROOT_DIR}/lib/common.sh"
|
||||
# shellcheck source=lib/persist.sh
|
||||
source "${ROOT_DIR}/lib/persist.sh"
|
||||
# shellcheck source=lib/iptables_ops.sh
|
||||
source "${ROOT_DIR}/lib/iptables_ops.sh"
|
||||
|
||||
uuid_v4=$("${ROOT_DIR}/iptables-forward.sh" --batch add tcp 65432 127.0.0.1 22 4 'integration-v4')
|
||||
assert_contains "$(iptables-save)" "MGMT:${uuid_v4}" 'IPv4 rule should appear in iptables-save output'
|
||||
assert_contains "$("${ROOT_DIR}/iptables-forward.sh" --batch list)" "uuid=${uuid_v4}" 'batch list should include managed rule'
|
||||
assert_file_contains "${PERSIST_RULES_V4}" "MGMT:${uuid_v4}" 'persist save should write IPv4 rules snapshot'
|
||||
assert_file_contains "${PERSIST_FIXTURE_LOG}" 'persist-fixture.sh save' 'adding a rule should call persist save'
|
||||
|
||||
ipt_remove_rule "${uuid_v4}" tcp 65432 127.0.0.1 22 4
|
||||
assert_status 1 "$(status_of grep -F "MGMT:${uuid_v4}" <(iptables-save))" 'manual runtime removal should clear managed IPv4 rule'
|
||||
|
||||
persist_reload
|
||||
assert_file_contains "${PERSIST_FIXTURE_LOG}" 'persist-fixture.sh reload' 'persist_reload should call persistence wrapper'
|
||||
assert_contains "$(iptables-save)" "MGMT:${uuid_v4}" 'persist_reload should restore IPv4 rule from snapshot'
|
||||
|
||||
iptables -A FORWARD -p tcp --dport 65000 -j ACCEPT
|
||||
|
||||
"${ROOT_DIR}/iptables-forward.sh" --batch delete "${uuid_v4}"
|
||||
assert_status 1 "$(status_of grep -F "MGMT:${uuid_v4}" <(iptables-save))" 'deleted IPv4 rule should disappear from iptables-save'
|
||||
assert_status 0 "$(status_of grep -F -- '--dport 65000 -j ACCEPT' <(iptables-save))" 'unmanaged rule should remain after deleting managed rule'
|
||||
assert_not_contains "$(cat "${PERSIST_RULES_V4}")" "MGMT:${uuid_v4}" 'deleting IPv4 rule should refresh persisted snapshot'
|
||||
|
||||
if command -v ip6tables >/dev/null 2>&1; then
|
||||
if command -v ip6tables >/dev/null 2>&1 && command -v ip6tables-save >/dev/null 2>&1 && command -v ip6tables-restore >/dev/null 2>&1; then
|
||||
uuid_v6=$("${ROOT_DIR}/iptables-forward.sh" --batch add tcp 65433 ::1 22 6 'integration-v6')
|
||||
assert_contains "$(ip6tables-save)" "MGMT:${uuid_v6}" 'IPv6 rule should appear in ip6tables-save output'
|
||||
assert_file_contains "${PERSIST_RULES_V6}" "MGMT:${uuid_v6}" 'persist save should write IPv6 rules snapshot'
|
||||
ipt_remove_rule "${uuid_v6}" tcp 65433 ::1 22 6
|
||||
assert_status 1 "$(status_of grep -F "MGMT:${uuid_v6}" <(ip6tables-save))" 'manual runtime removal should clear managed IPv6 rule'
|
||||
persist_reload
|
||||
assert_contains "$(ip6tables-save)" "MGMT:${uuid_v6}" 'persist_reload should restore IPv6 rule from snapshot'
|
||||
"${ROOT_DIR}/iptables-forward.sh" --batch delete "${uuid_v6}"
|
||||
assert_status 1 "$(status_of grep -F "MGMT:${uuid_v6}" <(ip6tables-save))" 'deleted IPv6 rule should disappear from ip6tables-save'
|
||||
assert_not_contains "$(cat "${PERSIST_RULES_V6}")" "MGMT:${uuid_v6}" 'deleting IPv6 rule should refresh persisted snapshot'
|
||||
fi
|
||||
|
||||
pass 'test_integration.sh'
|
||||
|
||||
Reference in New Issue
Block a user