89 lines
2.5 KiB
Bash
89 lines
2.5 KiB
Bash
#!/usr/bin/env bash
|
|
# Human-readable container RSS when rootless podman stats shows 0B / host RAM.
|
|
# Cause on openSUSE: user@.service Delegate= (20-defaults-SUSE.conf) clears
|
|
# memory/cpu controllers → no memory.current. CPU% from podman stats still works.
|
|
# Usage: podman-rss.sh [--json] [NAME_FILTER…]
|
|
set -euo pipefail
|
|
|
|
JSON=0
|
|
FILTERS=()
|
|
for a in "$@"; do
|
|
case "$a" in
|
|
--json|-j) JSON=1 ;;
|
|
-h|--help)
|
|
echo "usage: $0 [--json] [NAME_FILTER…]" >&2
|
|
exit 0
|
|
;;
|
|
*) FILTERS+=("$a") ;;
|
|
esac
|
|
done
|
|
|
|
human() {
|
|
# stdin: kibibytes integer
|
|
awk '
|
|
{
|
|
k=$1+0
|
|
if (k >= 1048576) printf "%.1f GiB", k/1048576
|
|
else if (k >= 1024) printf "%.0f MiB", k/1024
|
|
else printf "%d KiB", k
|
|
}'
|
|
}
|
|
|
|
# CPU map: name -> cpu%
|
|
declare -A CPU=()
|
|
while IFS=$'\t' read -r name cpu; do
|
|
[ -n "$name" ] || continue
|
|
CPU["$name"]="$cpu"
|
|
done < <(podman stats --no-stream --format '{{.Name}}\t{{.CPUPerc}}' 2>/dev/null || true)
|
|
|
|
rows=()
|
|
total_kib=0
|
|
while IFS= read -r cid; do
|
|
[ -n "$cid" ] || continue
|
|
name=$(podman inspect -f '{{.Name}}' "$cid" 2>/dev/null || true)
|
|
[ -n "$name" ] || continue
|
|
if [ ${#FILTERS[@]} -gt 0 ]; then
|
|
ok=0
|
|
for f in "${FILTERS[@]}"; do
|
|
case "$name" in *"$f"*) ok=1; break ;; esac
|
|
done
|
|
[ "$ok" -eq 1 ] || continue
|
|
fi
|
|
# podman top rss is KiB per process; sum
|
|
kib=$(podman top "$cid" -o rss 2>/dev/null | awk 'NR>1{s+=$1} END{print s+0}')
|
|
cpu="${CPU[$name]:-?}"
|
|
rows+=("${kib}|${name}|${cpu}")
|
|
total_kib=$((total_kib + kib))
|
|
done < <(podman ps -q)
|
|
|
|
IFS=$'\n' sorted=($(printf '%s\n' "${rows[@]:-}" | sort -t'|' -k1,1nr))
|
|
unset IFS
|
|
|
|
if [ "$JSON" -eq 1 ]; then
|
|
python3 - "$total_kib" "${sorted[@]:-}" <<'PY'
|
|
import json, sys
|
|
total = int(sys.argv[1]) if len(sys.argv) > 1 else 0
|
|
items = []
|
|
for row in sys.argv[2:]:
|
|
if not row.strip():
|
|
continue
|
|
kib, name, cpu = row.split("|", 2)
|
|
items.append({"name": name, "rss_kib": int(kib), "cpu": cpu})
|
|
print(json.dumps({"ok": True, "total_rss_kib": total, "containers": items}, indent=2))
|
|
PY
|
|
exit 0
|
|
fi
|
|
|
|
printf '%-44s %10s %8s\n' "NAME" "RSS" "CPU%"
|
|
printf '%-44s %10s %8s\n' "----" "---" "----"
|
|
for row in "${sorted[@]:-}"; do
|
|
[ -n "$row" ] || continue
|
|
kib="${row%%|*}"
|
|
rest="${row#*|}"
|
|
name="${rest%%|*}"
|
|
cpu="${rest##*|}"
|
|
hum=$(printf '%s' "$kib" | human)
|
|
printf '%-44s %10s %8s\n' "$name" "$hum" "$cpu"
|
|
done
|
|
printf '%-44s %10s\n' "TOTAL" "$(printf '%s' "$total_kib" | human)"
|
|
echo "# note: RSS via podman top (no memory cgroup); CPU via podman stats" >&2
|