Some of you have already noticed that I've changed employers. Thanks to this change, I have a new, big playground where I'm just starting to let loose. Today I discovered the huge storage system out in the field 😉
Today I discovered the big storage system out in the field 💾 Unfortunately, I don't have a central spot out there where I can keep an eye on all my toys. That's why I started setting up a Netbox https://netboxlabs.com/docs/netbox/ earlier this week and feeding it data accordingly
But all that work of gathering information is useless if the information isn't updated automatically. So I started adding the devices, models, and everything else you need to the Netbox. I got most of the hardware components set up pretty quickly using Netbox Data Exchange https://netboxlabs.com/ndx/. I had to build a few things myself, but then I was ready to start assembling.
#created by ♞ raffael.willems@imar-navigation.de
#!/usr/bin/env bash
set -euo pipefail
# needed params
NETBOX_URL="${NETBOX_URL:-defaulturl}"
NETBOX_TOKEN="${NETBOX_TOKEN:-avalidtoken}"
DEVICE_ID="${DEVICE_ID:-159}" # muss entsprechend fuer das jeweilige Treunas einmalig angepasst werden.
if [[ -z "$NETBOX_TOKEN" ]]; then
echo "Please set NETBOX_TOKEN" >&2
exit 1
fi
for cmd in zpool glabel midclt jq curl; do
command -v "$cmd" >/dev/null 2>&1 || {
echo "Missing required command: $cmd" >&2
exit 1
}
done
# get the gptids from zpool and put that info in a array
mapfile -t gptids < <(zpool status | awk '/raidz[0-9]/{n++; next} n==1 && /gptid\// {print $1} n>1{exit}')
# do we got gptids?
if [[ ${#gptids[@]} -eq 0 ]]; then
echo "No GPTIDs found in the first raidz vdev" >&2
exit 1
fi
# create a map and fill it with daX only (remove daXp entries)
declare -A gptid_to_da=()
while read -r name status comp; do
[[ -n "${comp:-}" ]] || continue
if [[ "$comp" =~ ^(da[0-9]+)(p[0-9]+)?$ ]]; then
da_base="${BASH_REMATCH[1]}"
gptid_to_da["$name"]="$da_base"
fi
done < <(glabel status)
mapfile -t da_names < <(
for g in "${gptids[@]}"; do
[[ -n "${gptid_to_da[$g]:-}" ]] && printf '%s\n' "${gptid_to_da[$g]}"
done
)
if [[ ${#da_names[@]} -eq 0 ]]; then
echo "No matching da names found for the GPTIDs" >&2
exit 1
fi
da_regex="$(printf '%s|' "${da_names[@]}")"
da_regex="^(${da_regex%|})$"
# create the Payload for the POST
midclt call disk.query |
jq -r '.[] | [.name, .serial, .type, .model] | @tsv' |
awk -F '\t' -v re="$da_regex" '$1 ~ re' |
while IFS=$'\t' read -r disk_name serial manufacturer part_id; do
[[ -n "${disk_name:-}" ]] || continue
payload=$(jq -n \
--arg device "$DEVICE_ID" \
--arg name "$disk_name" \
--arg serial "$serial" \
--arg part_id "$part_id" \
--arg manufacturer "$manufacturer" \
'{device: ($device | tonumber), name: $name, serial: $serial, part_id: $part_id, manufacturer: {name: $manufacturer}}')
response=$(curl -sS -w '\n%{http_code}' \
-X POST \
-H "Authorization: Token $NETBOX_TOKEN" \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
"$NETBOX_URL/api/dcim/inventory-items/" \
-d "$payload")
http_code=$(printf '%s\n' "$response" | tail -n1)
body=$(printf '%s\n' "$response" | sed '$d')
if [[ "$http_code" =~ ^2 ]]; then
echo "Created $disk_name: serial=$serial, manufacturer=$manufacturer, part_id=$part_id"
else
echo "Failed to create $disk_name: HTTP $http_code $body" >&2
fi
done