feat: --json output for group/rule/identity/net/activity

- cmd::group::_output_json: groups array with peer/blocked counts
- cmd::rule::_output_json: rules with extends array, is_base bool fix
- cmd::identity::_output_json: identities with types/rules as arrays
- cmd::net::_output_json: services with tags array and port count
- cmd::activity::_output_json: peers with nested services array
- all commands: command::mixin json_output registered in on_load
This commit is contained in:
Nuno Duque Nunes 2026-05-27 00:36:30 +00:00
parent fae088f61a
commit 087f735790
6 changed files with 201 additions and 3 deletions

View file

@ -14,6 +14,8 @@ function cmd::activity::on_load() {
flag::register --hours flag::register --hours
flag::register --type flag::register --type
flag::register --dropped flag::register --dropped
command::mixin json_output
} }
# ============================================ # ============================================
@ -70,6 +72,11 @@ function cmd::activity::run() {
esac esac
done done
if command::json; then
cmd::activity::_output_json "$hours"
return 0
fi
# Resolve peer name if type provided # Resolve peer name if type provided
if [[ -n "$filter_peer" && -n "$filter_type" ]]; then if [[ -n "$filter_peer" && -n "$filter_type" ]]; then
filter_peer=$(peers::resolve_and_require "$filter_peer" "$filter_type") || return 1 filter_peer=$(peers::resolve_and_require "$filter_peer" "$filter_type") || return 1
@ -188,3 +195,51 @@ function cmd::activity::run() {
echo "" echo ""
} }
function cmd::activity::_output_json() {
local hours="${1:-24}"
local data
data=$(json::activity_aggregate \
"$(ctx::fw_events_log)" "$(ctx::events_log)" \
"$(config::interface)" "$(ctx::net)" \
"$(ctx::clients)" "$(ctx::meta)" \
"$hours" "" "" 2>/dev/null)
local -a peers=()
local current_peer="" current_services=""
local -a current_svc_list=()
while IFS='|' read -r record_type rest; do
case "$record_type" in
peer)
# Flush previous peer
if [[ -n "$current_peer" ]]; then
local svc_array
svc_array=$(printf '%s\n' "${current_svc_list[@]:-}" | paste -sd ',' -)
peers+=("${current_peer},\"services\":[${svc_array:-}]}")
current_svc_list=()
fi
local name rx tx drops
IFS='|' read -r name rx tx drops <<< "$rest"
current_peer=$(printf '{"name":"%s","rx":%s,"tx":%s,"drops":%s' \
"$name" "$rx" "$tx" "$drops")
;;
service)
local peer dest count
IFS='|' read -r peer dest count <<< "$rest"
current_svc_list+=("$(printf '{"dest":"%s","drops":%s}' "$dest" "$count")")
;;
esac
done <<< "$data"
# Flush last peer
if [[ -n "$current_peer" ]]; then
local svc_array
svc_array=$(printf '%s\n' "${current_svc_list[@]:-}" | paste -sd ',' -)
peers+=("${current_peer},\"services\":[${svc_array:-}]}")
fi
local count=${#peers[@]}
local array
array=$(printf '%s\n' "${peers[@]:-}" | paste -sd ',' -)
printf '{"peers":[%s]}' "${array:-}" | json::envelope "activity" "$count"
}

View file

@ -15,6 +15,7 @@ function cmd::group::on_load() {
flag::register --force flag::register --force
flag::register --all flag::register --all
flag::register --dry-run flag::register --dry-run
command::mixin json_output
} }
# ============================================ # ============================================
@ -83,6 +84,11 @@ function cmd::group::run() {
local subcmd="${1:-help}" local subcmd="${1:-help}"
shift || true shift || true
if command::json; then
cmd::group::_output_json
return 0
fi
case "$subcmd" in case "$subcmd" in
list|ls) cmd::group::list "$@" ;; list|ls) cmd::group::list "$@" ;;
show) cmd::group::show "$@" ;; show) cmd::group::show "$@" ;;
@ -908,4 +914,23 @@ function cmd::group::purge_stale() {
log::wg_success "${action} ${total_removed} stale peer(s)..." log::wg_success "${action} ${total_removed} stale peer(s)..."
fi fi
fi fi
}
function cmd::group::_output_json() {
local groups_dir
groups_dir="$(ctx::groups)"
local data
data=$(json::group_list_data "$groups_dir" "$(ctx::blocks)" "$(ctx::clients)" 2>/dev/null)
local -a groups=()
while IFS='|' read -r name desc peer_count blocked_count; do
[[ -z "$name" ]] && continue
groups+=("$(printf '{"name":"%s","desc":"%s","peer_count":%s,"blocked_count":%s}' \
"$name" "$desc" "$peer_count" "$blocked_count")")
done <<< "$data"
local count=${#groups[@]}
local array
array=$(printf '%s\n' "${groups[@]:-}" | paste -sd ',' -)
printf '{"groups":[%s]}' "${array:-}" | json::envelope "group list" "$count"
} }

View file

@ -20,9 +20,7 @@ function cmd::identity::on_load() {
flag::register --peer flag::register --peer
flag::register --dry-run flag::register --dry-run
flag::register --force flag::register --force
# rule subcommand flags
flag::register --rule flag::register --rule
# options subcommand flags
flag::register --policy flag::register --policy
flag::register --set-strict-rule flag::register --set-strict-rule
flag::register --unset-strict-rule flag::register --unset-strict-rule
@ -31,6 +29,8 @@ function cmd::identity::on_load() {
flag::register --field flag::register --field
flag::register --value flag::register --value
flag::register --migrate flag::register --migrate
command::mixin json_output
} }
# ============================================ # ============================================
@ -78,6 +78,11 @@ function cmd::identity::run() {
local subcmd="${1:-list}" local subcmd="${1:-list}"
shift || true shift || true
if command::json && [[ "$subcmd" == "list" ]]; then
cmd::identity::_output_json
return 0
fi
case "$subcmd" in case "$subcmd" in
list) cmd::identity::_list "$@" ;; list) cmd::identity::_list "$@" ;;
show) cmd::identity::_show "$@" ;; show) cmd::identity::_show "$@" ;;
@ -565,4 +570,41 @@ function cmd::identity::_options() {
if ! $changed; then if ! $changed; then
cmd::identity::_rule_show --name "$name" cmd::identity::_rule_show --name "$name"
fi fi
} }
function cmd::identity::_output_json() {
local data
data=$(identity::list_data 2>/dev/null)
local -a identities=()
while IFS='|' read -r name peer_count types rules policy; do
[[ -z "$name" ]] && continue
# Build rules array
local rules_json="[]"
if [[ -n "$rules" ]]; then
local rules_array
rules_array=$(echo "$rules" | tr ',' '\n' | \
while IFS= read -r r; do [[ -n "$r" ]] && printf '"%s",' "$r"; done | sed 's/,$//')
rules_json="[${rules_array}]"
fi
# Build types array (was comma-separated string)
local types_json="[]"
if [[ -n "$types" ]]; then
local types_array
types_array=$(echo "$types" | tr ',' '\n' | \
while IFS= read -r t; do [[ -n "$t" ]] && printf '"%s",' "$t"; done | sed 's/,$//')
types_json="[${types_array}]"
fi
identities+=("$(printf '{"name":"%s","peer_count":%s,"types":%s,"rules":%s,"policy":"%s"}' \
"$name" "$peer_count" "$types_json" "$rules_json" "$policy")")
done <<< "$data"
local count=${#identities[@]}
local array
array=$(printf '%s\n' "${identities[@]:-}" | paste -sd ',' -)
printf '{"identities":[%s]}' "${array:-}" | json::envelope "identity list" "$count"
}

View file

@ -8,6 +8,8 @@ function cmd::net::on_load() {
flag::register --tag flag::register --tag
flag::register --detailed flag::register --detailed
flag::register --force flag::register --force
command::mixin json_output
} }
function cmd::net::help() { function cmd::net::help() {
@ -58,6 +60,12 @@ EOF
function cmd::net::run() { function cmd::net::run() {
local subcmd="${1:-list}" local subcmd="${1:-list}"
shift || true shift || true
if command::json; then
cmd::net::_output_json
return 0
fi
case "$subcmd" in case "$subcmd" in
list) cmd::net::list "$@" ;; list) cmd::net::list "$@" ;;
show) cmd::net::show "$@" ;; show) cmd::net::show "$@" ;;
@ -304,4 +312,31 @@ function cmd::net::rm() {
json::net_remove "$(ctx::net)" "$name" json::net_remove "$(ctx::net)" "$name"
log::wg_success "Removed: ${name}" log::wg_success "Removed: ${name}"
return 0 return 0
}
function cmd::net::_output_json() {
local net_file
net_file="$(ctx::net)"
local data
data=$(json::net_list "$net_file" 2>/dev/null)
local -a services=()
while IFS='|' read -r name ip desc tags port_count; do
[[ -z "$name" ]] && continue
# Build tags array
local tags_json="[]"
if [[ -n "$tags" ]]; then
local tags_array
tags_array=$(echo "$tags" | tr ',' '\n' | \
while IFS= read -r t; do [[ -n "$t" ]] && printf '"%s",' "$t"; done | sed 's/,$//')
tags_json="[${tags_array}]"
fi
services+=("$(printf '{"name":"%s","ip":"%s","desc":"%s","tags":%s,"port_count":%s}' \
"$name" "$ip" "$desc" "$tags_json" "$port_count")")
done <<< "$data"
local count=${#services[@]}
local array
array=$(printf '%s\n' "${services[@]:-}" | paste -sd ',' -)
printf '{"services":[%s]}' "${array:-}" | json::envelope "net list" "$count"
} }

View file

@ -31,6 +31,8 @@ function cmd::rule::on_load() {
flag::register --force flag::register --force
flag::register --type flag::register --type
flag::register --all flag::register --all
command::mixin json_output
} }
# ============================================ # ============================================
@ -116,6 +118,11 @@ function cmd::rule::run() {
local subcmd="${1:-help}" local subcmd="${1:-help}"
shift || true shift || true
if command::json; then
cmd::rule::_output_json
return 0
fi
case "$subcmd" in case "$subcmd" in
list|ls) cmd::rule::list "$@" ;; list|ls) cmd::rule::list "$@" ;;
show|inspect) cmd::rule::show "$@" ;; show|inspect) cmd::rule::show "$@" ;;
@ -671,4 +678,38 @@ function cmd::rule::reapply() {
rule::require_exists "$name" || return 1 rule::require_exists "$name" || return 1
rule::reapply_all "$name" rule::reapply_all "$name"
log::wg_success "Rule '${name}' reapplied" log::wg_success "Rule '${name}' reapplied"
}
function cmd::rule::_output_json() {
local rules_dir
rules_dir="$(ctx::rules)"
local data
data=$(json::rule_list_data "$rules_dir" "$(ctx::meta)" 2>/dev/null)
local -a rules=()
while IFS='|' read -r name desc n_allows n_blocks peer_count extends is_base group; do
[[ -z "$name" ]] && continue
# Build extends array
local extends_json="[]"
if [[ -n "$extends" ]]; then
local ext_array
ext_array=$(echo "$extends" | tr ',' '\n' | \
while IFS= read -r e; do [[ -n "$e" ]] && printf '"%s",' "$e"; done | sed 's/,$//')
extends_json="[${ext_array}]"
fi
# Convert Python bool to JSON bool
local is_base_json="false"
[[ "$is_base" == "True" ]] && is_base_json="true"
rules+=("$(printf '{"name":"%s","desc":"%s","allows":%s,"blocks":%s,"peer_count":%s,"extends":%s,"is_base":%s,"group":"%s"}' \
"$name" "$desc" "$n_allows" "$n_blocks" "$peer_count" \
"$extends_json" "$is_base_json" "$group")")
done <<< "$data"
local count=${#rules[@]}
local array
array=$(printf '%s\n' "${rules[@]:-}" | paste -sd ',' -)
printf '{"rules":[%s]}' "${array:-}" | json::envelope "rule list" "$count"
} }