NETBOX - NetBox VLAN Device List Discovery.sh

From IT-Arts.net


Return to Wiki Index


NetBox_VLAN_Device_List_Discovery.sh

#!/usr/bin/env bash
#
#	THIS SCRIPT EXTRACT ALL HOST/INTERFACES CONFIGURED WITH GIVEN VLAN
#
#	THIS SCRIPT NEED BASH 4+ AND JQ
#	NETBOX VERSION 4.6.x
#
########################################################################

set -euo pipefail

# =========================
# USAGE FUNCTION
# =========================

usage() {
  echo "USAGE: $0 -h <FQDN> -t <TOKEN> -v <VLAN_VID1> <VLAN_VID2>...  [-d]"
  echo "-h : FQDN OF NETBOX INSTANCE"
  echo "-t : API TOKEN FOR AUTHENTICATION"
  echo "-v : LIST OF VLAN VIDS TO SEARCH (NOT VLAN IDs)"
  echo "-d : ENABLE DEBUG OUTPUT"
  exit 1
}

# =========================
# INPUT VARIABLES
# =========================

HOST=""        # NETBOX FQDN (WITHOUT HTTPS PREFIX)
TOKEN=""       # NETBOX API TOKEN
DEBUG=0        # DEBUG MODE FLAG (0=OFF, 1=ON)
VIDS=()        # LIST OF VLAN VIDS PASSED BY USER


# =========================
# ARGUMENT PARSING
# =========================

while [[ $# -gt 0 ]]; do
  case "$1" in
    -h) HOST="${2:-}"; shift 2 ;;   # SET NETBOX HOST
    -t) TOKEN="${2:-}"; shift 2 ;;  # SET API TOKEN
    -v)
      shift
      # COLLECT MULTIPLE VLAN VIDS UNTIL NEXT OPTION
      while [[ $# -gt 0 && "$1" != -* ]]; do
        VIDS+=("$1")
        shift
      done
      ;;
    -d) DEBUG=1; shift ;;           # ENABLE DEBUG MODE
    *) usage ;;                     # INVALID OPTION
  esac
done

# ENSURE REQUIRED PARAMETERS ARE PRESENT
[[ -z "$HOST" || -z "$TOKEN" || ${#VIDS[@]} -eq 0 ]] && usage

# =========================
# API CONFIGURATION
# =========================

API="https://${HOST}/api"
AUTH="Authorization: Token ${TOKEN}"

# =========================
# API CALL WRAPPER FUNCTION
# =========================

api() {
  local url="$1"

  # DEBUG OUTPUT FOR API CALLS
  [[ $DEBUG -eq 1 ]] && echo "[DEBUG] GET $url" >&2

  # PERFORM REQUEST
  resp=$(curl -sS -H "$AUTH" -H "Accept: application/json" "$url")

  # VALIDATE JSON RESPONSE
  echo "$resp" | jq -e . >/dev/null 2>&1 || {
    echo "[ERROR] INVALID JSON RESPONSE: $url" >&2
    echo "$resp" | head -n 10 >&2
    return 1
  }

  echo "$resp"
}

# =========================
# OUTPUT HEADER
# =========================

echo "DEVICE, VLAN VID, VLAN NAME, INTERFACE, MODE, INTERFACE DESCRIPTION"

# PRELOAD ALL INTERFACES ONCE (PERFORMANCE OPTIMIZATION)
interfaces=$(api "${API}/dcim/interfaces/?limit=1000")

# =========================
# MAIN PROCESS LOOP
# =========================

for vid in "${VIDS[@]}"; do

  # FETCH VLAN OBJECTS MATCHING GIVEN VID
  vlan_json=$(api "${API}/ipam/vlans/?vid=${vid}&limit=1000")

  # COUNT HOW MANY VLAN OBJECTS MATCH THIS VID
  vlan_count=$(echo "$vlan_json" | jq '.results | length')

  # IF NO VLAN FOUND, REPORT IT
  if [[ "$vlan_count" -eq 0 ]]; then
    echo "VLAN ${vid} IS NOT PRESENT"
    continue
  fi

  # LOOP THROUGH ALL VLAN OBJECTS (IMPORTANT: SAME VID CAN HAVE MULTIPLE VLANS)
  echo "$vlan_json" | jq -c '.results[]' | while read -r vlan; do

    # EXTRACT VLAN INTERNAL ID (NETBOX OBJECT ID)
    vlan_id=$(echo "$vlan" | jq -r '.id')

    # EXTRACT VLAN NAME
    vlan_name=$(echo "$vlan" | jq -r '.name')

    # DEBUG INFO PER VLAN OBJECT
    [[ $DEBUG -eq 1 ]] && echo "[DEBUG] VID=$vid VLAN_ID=$vlan_id NAME=$vlan_name" >&2

    # PROCESS ALL INTERFACES AGAINST THIS VLAN OBJECT
    echo "$interfaces" | jq -r \
      --arg vid "$vid" \
      --arg vlan_id "$vlan_id" \
      --arg name "$vlan_name" '
      .results[] |

      # DEVICE NAME
      .device.name as $device |

      # INTERFACE NAME
      .name as $iface |

      # INTERFACE DESCRIPTION (DEFAULT IF EMPTY)
      (.description // "—") as $desc |

      # LIST OF TAGGED VLANS ON INTERFACE
      (.tagged_vlans // []) as $tagged_list |

      # CHECK IF CURRENT VLAN IS TAGGED
      ($tagged_list | map(.id | tostring) | index($vlan_id)) as $is_tagged |

      # CHECK IF CURRENT VLAN IS UNTAGGED
      (.untagged_vlan?.id | tostring == $vlan_id) as $is_untagged |

      # OUTPUT FORMATTING
      if $is_tagged then
        "\($device), \($vid), \($name), \($iface), TAGGED, \($desc)"
      elif $is_untagged then
        "\($device), \($vid), \($name), \($iface), UNTAGGED, \($desc)"
      else
        empty
      end
    '

  done

done | sort -u

Return to Wiki Index