reefland / motd

Custom Message of the Day for Linux with ZFS Enhancements
12 stars 0 forks source link

ZFS dataset stats #2

Open mroach opened 2 weeks ago

mroach commented 2 weeks ago

Is your feature request related to a problem ?

Hello! This isn't so much a feature request as a submission of an idea with proof of concept code.

The zpool bar doesn't show the actual capacity of pools, but rather the total size of disks in the pool. Not a big deal.

In my setup I'm using multiple datasets, each with their own quotas. I wanted to see these as part of the MOTD.

Also, when a dataset is using significant space on snapshots, I wanted to visualise that in the bar.

Describe the solution you'd like.

Describe alternatives you've considered.

This script is my first pass at it. I wanted to share it if you think there's value in adding it or a variant of it to the repo as a ZFS option.

Screenshot from 2024-10-13 15-48-53

#!/usr/bin/env bash

set -euo pipefail

size_format=iec
bar_width=60
warn_free_pct=20
red="\e[1;31m"
green="\e[1;32m"
dim="\e[2m"
reset="\e[0m"
ds_char="■"
snap_char="◆"
other_char="▦"
free_char="□"

function format_bytes() {
  numfmt --to="${size_format}" --format="%.01f" "$1"
}

function pct() {
  awk -v n="$1" -v d="$2" 'BEGIN{ print int(n*100.0/d) }'
}

function bar() {
  ds_b="$1"
  snap_b="$2"
  other_b="$3"

  ds_width=$(( (ds_b * bar_width) / 100))
  snap_width=$(( (snap_b * bar_width) / 100))
  other_width=$(( (other_b * bar_width) / 100 ))
  rem=$(( bar_width - ds_width - snap_width - other_width ))

  pct_free=$(( 100 - ds_width - snap_width - other_width ))

  echo -ne "${dim}[${reset}"

  if [ "$pct_free" -lt "$warn_free_pct" ]; then
    echo -ne "$red"
  else
    echo -ne "$green"
  fi

  if [ $ds_width -gt 0 ]; then
    printf "${ds_char}%.0s" $(seq 1 $ds_width)
  fi

  if [ $snap_width -gt 0 ]; then
    printf "${snap_char}%.0s" $(seq 1 $snap_width)
  fi

  if [ $other_width -gt 0 ]; then
    printf "${other_char}%.0s" $(seq 1 $other_width)
  fi

  if [ $rem -gt 0 ]; then
    printf "${dim}${free_char}%.0s" $(seq 1 $rem)
    # To pad with spaces, do this instead:
    #printf "${dim}%*s" $rem
  fi

  echo -e "${reset}${dim}]${reset}"
}

echo

while read -r line; do
  IFS=$'\t' read -r -a props <<< "$line"

  name="${props[0]}"
  avail="${props[1]}"
  used="${props[2]}"
  usedsnap="${props[3]}"
  usedds="${props[4]}"

  used_other=$(( used - usedsnap - usedds ))
  capacity=$(( used + avail ))

  ds_used_pct=$(pct "$usedds" "$capacity")
  snap_used_pct=$(pct "$usedsnap" "$capacity")
  other_used_pct=$(pct "$used_other" "$capacity")

  #echo "$name avail=$avail used=$used usnap=$usedsnap uds=$usedds cap=$capacity dp=$ds_used_pct sp=$snap_used_pct"

  # Maybe remove the pool name
  local_name="${name#*/}"
  if [ "$local_name" = "$name" ]; then
    echo "$name"
  else
    echo "  $local_name"
  fi
  echo -n "  "
  bar "$ds_used_pct" "$snap_used_pct" "$other_used_pct"
  echo -n "   "
  printf "Used %s of %s (%s free)\n\n" "$(format_bytes $used)" "$(format_bytes $capacity)" "$(format_bytes $avail)"
done < <(zfs list -Hp -t filesystem -o space -d1)

Or with a few tweaks, a compact layout:

Screenshot from 2024-10-13 16-19-53

Additional context.

No response

reefland commented 1 week ago

Thank you for sharing! I'll check it out in a bit.