feat: group purge-stale, peer endpoint history, resolve improvements
- group purge-stale: remove stale peers from group(s), --all, --dry-run
- daemon: update_peer_history() tracks all endpoints per peer
- daemon: endpoint_index.json for O(1) IP -> peer name lookup
- json_helper: peer_history_lookup() with index + scan fallback
- resolve::endpoint_parts: peer history as step 3 in resolution chain
- resolve::service_name: returns service name only, no raw fallback
- resolve::endpoint_parts: removed stale cache, always fresh
- watch: ui:⌚:wg_row/fw_row use shared primitives
- ui: ui::_render_endpoint_col, ui::_build_dest shared primitives
- shell: peer/hosts/identity/subnet/policy/activity in known commands
This commit is contained in:
parent
8b47e55b4a
commit
adab623f3f
1 changed files with 96 additions and 0 deletions
|
|
@ -13,6 +13,8 @@ function cmd::group::on_load() {
|
|||
flag::register --new-name
|
||||
flag::register --main
|
||||
flag::register --force
|
||||
flag::register --all
|
||||
flag::register --dry-run
|
||||
}
|
||||
|
||||
# ============================================
|
||||
|
|
@ -37,6 +39,7 @@ Subcommands:
|
|||
peer add Add a peer to a group
|
||||
peer remove, peer rm Remove a peer from a group
|
||||
rm-peers Remove all peers in group from WireGuard
|
||||
purge-stale Remove peers that no longer exist from group(s)
|
||||
block Block all peers in group
|
||||
unblock Unblock all peers in group
|
||||
rule assign Assign a rule to all peers in group
|
||||
|
|
@ -53,6 +56,7 @@ Options:
|
|||
--new-name <name> New group name (for rename)
|
||||
--limit <n> Max log entries per peer (for logs)
|
||||
--force Skip confirmation prompts
|
||||
--all Apply to all groups (for purge-stale)
|
||||
|
||||
Examples:
|
||||
wgctl group list
|
||||
|
|
@ -62,6 +66,9 @@ Examples:
|
|||
wgctl group block --name family
|
||||
wgctl group unblock --name family
|
||||
wgctl group rule assign --name family --rule user
|
||||
wgctl group purge-stale --name family
|
||||
wgctl group purge-stale --all
|
||||
wgctl group purge-stale --all --force
|
||||
wgctl group audit --name family
|
||||
wgctl group logs --name family --limit 20
|
||||
wgctl group watch --name family
|
||||
|
|
@ -88,6 +95,7 @@ function cmd::group::run() {
|
|||
block) cmd::group::block "$@" ;;
|
||||
unblock) cmd::group::unblock "$@" ;;
|
||||
rule) cmd::group::rule "$@" ;;
|
||||
purge-stale) cmd::group::purge_stale "$@" ;;
|
||||
audit) cmd::group::audit "$@" ;;
|
||||
logs) cmd::group::logs "$@" ;;
|
||||
watch) cmd::group::watch "$@" ;;
|
||||
|
|
@ -813,3 +821,91 @@ function cmd::group::watch() {
|
|||
load_command watch
|
||||
cmd::watch::run --peers "$peer_filter"
|
||||
}
|
||||
|
||||
# ============================================
|
||||
# Purge Stale
|
||||
# ============================================
|
||||
|
||||
function cmd::group::purge_stale() {
|
||||
local name="" force=false all=false
|
||||
local dry_run=false
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--name) util::require_flag "--name" "${2:-}" || return 1; name="$2"; shift 2 ;;
|
||||
--force) force=true; shift ;;
|
||||
--all) all=true; shift ;;
|
||||
--dry-run) dry_run=true; shift ;;
|
||||
--help) cmd::group::help; return ;;
|
||||
*) log::error "Unknown flag: $1"; return 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
[[ -z "$name" && "$all" == "false" ]] && \
|
||||
log::error "Specify --name <group> or --all" && return 1
|
||||
|
||||
# Build list of groups to process
|
||||
local -a groups=()
|
||||
if $all; then
|
||||
while IFS= read -r group_file; do
|
||||
groups+=("$(basename "$group_file" .group)")
|
||||
done < <(find "$(ctx::groups)" -name "*.group" 2>/dev/null | sort)
|
||||
else
|
||||
group::require_exists "$name" || return 1
|
||||
groups=("$name")
|
||||
fi
|
||||
|
||||
local total_removed=0 total_groups=0
|
||||
|
||||
for group_name in "${groups[@]}"; do
|
||||
[[ -z "$group_name" ]] && continue
|
||||
|
||||
# Find stale peers — in group but no .conf file
|
||||
local -a stale=()
|
||||
while IFS= read -r peer_name; do
|
||||
[[ -z "$peer_name" ]] && continue
|
||||
if [[ ! -f "$(ctx::clients)/${peer_name}.conf" ]]; then
|
||||
stale+=("$peer_name")
|
||||
fi
|
||||
done < <(group::peers "$group_name" 2>/dev/null)
|
||||
|
||||
[[ ${#stale[@]} -eq 0 ]] && continue
|
||||
|
||||
(( total_groups++ )) || true
|
||||
|
||||
if ! $force; then
|
||||
printf " Group '%s' has %d stale peer(s): %s\n" \
|
||||
"$group_name" "${#stale[@]}" "${stale[*]}"
|
||||
read -r -p " Remove them? [y/N] " confirm
|
||||
case "$confirm" in
|
||||
[yY]*) ;;
|
||||
*) log::info "Skipped '${group_name}'"; continue ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
local group_file
|
||||
group_file="$(group::path "$group_name")"
|
||||
for peer_name in "${stale[@]}"; do
|
||||
if $dry_run; then
|
||||
printf " \033[2m[dry-run]\033[0m Would remove '%s' from group '%s'\n" \
|
||||
"$peer_name" "$group_name"
|
||||
else
|
||||
json::remove "$group_file" "peers" "$peer_name" 2>/dev/null || true
|
||||
log::debug "Removed stale peer '${peer_name}' from group '${group_name}'"
|
||||
fi
|
||||
(( total_removed++ )) || true
|
||||
done
|
||||
done
|
||||
|
||||
local action="Removed"
|
||||
$dry_run && action="Would remove"
|
||||
log::wg_success "${action} ${total_removed} stale peer(s)..."
|
||||
|
||||
if $all; then
|
||||
if [[ "$total_removed" -eq 0 ]]; then
|
||||
log::wg_warning "No stale peers found in any group"
|
||||
else
|
||||
log::wg_success "${action} ${total_removed} stale peer(s)..."
|
||||
fi
|
||||
fi
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue