scripts/discover-*: four QoL upgrades from first live gap-analysis run

First real run surfaced 31 gap rows, ~20 of which were noise. These
changes reduce the output to actionable signal.

1. discover-unifi: /ea/devices now filters out
     - IPs outside the fleet LAN range (UDM's WAN IP appearing as a
       "device", ISP uplink records with public IPs)
     - UDM self-records (isConsole=true, or IP matches wans[].ipv4)
     - UCI records (UniFi Cable Internet = ISP modem tracking)
   LAN filter regex defaults to ^10\. (matches 10.0.0.0/8); override
   via UNIFI_LAN_FILTER env var if you run other private ranges.

2. discover-gaps: new --ignore-unifi flag drops rows where the final
   SOURCE column starts with "unifi:". Useful for "show me servery
   things to manage, not the fleet's network hardware."

3. discover-gaps: known-IP set now pulls IPs from
   servers/*/proxmox-details.txt AND servers/*/system-details.txt in
   addition to README.md and ssh-target. Consequence: VMs tracked by
   proxmox_inspect.sh are automatically counted as known without
   needing a separate servers/<vmname>/ dir. Also strips meaningless
   addresses (127.*, 0.0.0.0, 169.254.*) so they can't false-positive
   a "known" match.

4. MAC normalization: both discover-fortigate and discover-unifi now
   emit xx:xx:xx:xx:xx:xx lowercase. Previously FortiGate used colon
   format, UniFi used no-separator uppercase — same MAC looked
   different per source. Fortigate does tolower() in awk; UniFi uses
   a shared jq `norm_mac` function.
This commit is contained in:
vh
2026-04-21 14:19:12 -07:00
parent 57c944ad5f
commit b33439499b
3 changed files with 111 additions and 25 deletions
+41 -5
View File
@@ -110,12 +110,31 @@ ui_get() {
# Endpoint-specific TSV formatters
# ----------------------------------------------------------------------
# Shared jq prelude: normalize MAC to xx:xx:xx:xx:xx:xx lowercase so
# output aligns with the FortiGate format.
JQ_PRELUDE='
def norm_mac:
. as $m |
if $m == null or $m == "-" then "-"
else
($m | ascii_downcase | gsub("[^0-9a-f]"; "")) as $h |
if ($h | length) == 12 then
($h[0:2] + ":" + $h[2:4] + ":" + $h[4:6] + ":" + $h[6:8] + ":" + $h[8:10] + ":" + $h[10:12])
else $m
end
end;
'
# LAN filter regex. Default matches the fleet's 10.x.x.x space; override
# with UNIFI_LAN_FILTER if you run a different private range.
LAN_FILTER="${UNIFI_LAN_FILTER:-^10\\.}"
emit_hosts() {
# LAN IP is the first RFC1918 entry in reportedState.ipAddrs that is
# NOT also present as a WAN ipv4 (reportedState.wans[]) — UDMs with
# RFC1918-addressed WAN2 interfaces would otherwise get mis-picked as
# their LAN IP. Falls back through the usual chain if nothing matches.
ui_get /ea/hosts | jq -r '
ui_get /ea/hosts | jq -r "$JQ_PRELUDE"'
. as $h |
(($h.reportedState.wans // []) | map(.ipv4 // empty)) as $wans |
[
@@ -129,7 +148,7 @@ emit_hosts() {
)] | .[0])
// .reportedState.ip // .ipAddress // "-"
),
(.reportedState.mac // "-"),
((.reportedState.mac // "-") | norm_mac),
(.reportedState.hostname // .reportedState.name // "-"),
(.reportedState.hardware.shortname // .reportedState.hardware.name // .type // "-"),
(.reportedState.version // "-"),
@@ -152,13 +171,30 @@ emit_sites() {
}
emit_devices() {
# /ea/devices returns per-host wrappers; flatten into one row per AP/switch.
ui_get /ea/devices | jq -r '
# /ea/devices returns per-host wrappers; flatten into one row per
# AP/switch. Drop entries that clutter gap analysis without adding value:
# - IPs outside the fleet LAN range (UDM's public WAN IP listed as
# a "device", etc.)
# - UDM self-records (isConsole=true or their WAN IP matches a
# wans[].ipv4 — the UDM itself shows up in its own devices list)
# - UCI records (UniFi Cable Internet = ISP uplink tracking, model="UCI")
ui_get /ea/devices | jq -r \
--arg lan "$LAN_FILTER" \
"$JQ_PRELUDE"'
. as $h |
(($h.wans // []) | map(.ipv4 // empty)) as $wans |
(.devices // [])[] |
select(
(.ip // "") | test($lan)
) |
select(
(.isConsole // false) != true and
(.model // "") != "UCI" and
(.ip as $ip | ($wans | index($ip)) == null)
) |
[
(.ip // "-"),
(.mac // .id // "-"),
((.mac // .id // "-") | norm_mac),
(.name // "-"),
(.model // .shortname // "-"),
($h.hostName // $h.hostId // "-"),