Skip to content

Commit

Permalink
added script to check how many pgs per osd per pool per ceph cluster …
Browse files Browse the repository at this point in the history
…per mike mcphee
  • Loading branch information
baileyallison committed Feb 11, 2025
1 parent 701a26b commit 9976181
Showing 1 changed file with 158 additions and 0 deletions.
158 changes: 158 additions & 0 deletions pg_info.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
#!/usr/bin/env bash
#
# pg_per_osd_ec_replicated.sh
#
# 1) Gets total OSD count from the cluster.
# 2) Lists each pool, checks if it's replicated or erasure-coded.
# - For replicated pools, uses (pg_num * size) / OSD_COUNT.
# - For EC pools, retrieves (k+m) from the pool's erasure-code profile,
# then uses (pg_num * (k + m)) / OSD_COUNT.
# 3) Prints the "PG per OSD" for each pool.
#
# Requirements:
# - ceph CLI
# - jq

set -e

# ------------------------------------------------------------------------------
# 1) Get total number of OSDs
# ------------------------------------------------------------------------------
OSD_COUNT=$(ceph osd stat --format json | jq -r '.num_osds')
if [[ -z "$OSD_COUNT" || "$OSD_COUNT" -le 0 ]]; then
echo "ERROR: Could not retrieve a valid OSD count!"
exit 1
fi

# ------------------------------------------------------------------------------
# 2) Get pool details (type, size, pg_num, erasure_code_profile, etc.)
# "ceph osd pool ls detail --format json" returns an array of pools.
# ------------------------------------------------------------------------------
POOL_DETAILS=$(ceph osd pool ls detail --format json)
if [[ -z "$POOL_DETAILS" ]]; then
echo "ERROR: Could not retrieve pool details!"
exit 1
fi

# We'll parse .type to see if it's replicated or ec.
# For Ceph versions:
# type = 1 => replicated
# type = 3 => erasure-coded
#
# (There might be older or alternate representations, but this is standard.)
#

# ------------------------------------------------------------------------------
# Function to retrieve and cache 'k' and 'm' for a given EC profile
# ------------------------------------------------------------------------------
declare -A EC_K
declare -A EC_M

get_ec_params() {
local profile="$1"

# If we've already cached this profile, skip the CLI call
if [[ -n "${EC_K[$profile]}" && -n "${EC_M[$profile]}" ]]; then
return
fi

# Retrieve the profile as JSON, e.g.:
# {
# "k": "2",
# "m": "1",
# ...
# }
local profile_json
profile_json=$(ceph osd erasure-code-profile get "$profile" --format json)

# Extract k, m
local k_val m_val
# shellcheck disable=SC2086
read -r k_val m_val < <(echo "$profile_json" | jq -r '[.k, .m] | @sh' | xargs echo)

# Cache them
EC_K["$profile"]="$k_val"
EC_M["$profile"]="$m_val"
}

# ------------------------------------------------------------------------------
# 3) Loop over each pool and compute PG per OSD
# ------------------------------------------------------------------------------
echo "Total OSDs in cluster: $OSD_COUNT"
echo "=========================================================="

# We'll use jq to extract the needed fields and iterate:
echo "$POOL_DETAILS" | jq -r '
.[] |
{
name: .pool_name,
pg_num: .pg_num,
type: .type,
size: (if .type == 1 then .size else null end),
ec_profile: (if .type == 3 then .erasure_code_profile else null end)
} |
"\(.name)\t\(.pg_num)\t\(.type)\t\(.size)\t\(.ec_profile)"
' | while IFS=$'\t' read -r POOL_NAME POOL_PG POOL_TYPE POOL_SIZE EC_PROFILE; do

# POOL_TYPE=1 => replicated, POOL_TYPE=3 => EC
if [[ "$POOL_TYPE" -eq 1 ]]; then
# Replicated pool
# Formula: PG per OSD = (pg_num * size) / OSD_COUNT
if [[ -z "$POOL_SIZE" ]]; then
echo "ERROR: Replicated pool '$POOL_NAME' has no 'size' field!"
continue
fi

PG_PER_OSD=$(awk -v pg="$POOL_PG" -v sz="$POOL_SIZE" -v osd="$OSD_COUNT" '
BEGIN {
val = (pg * sz) / osd;
printf "%.2f", val;
}'
)
echo -e "Pool Name: \e[31m$POOL_NAME\e[0m"
echo " Type : Replicated"
echo " Replication size : $POOL_SIZE"
echo " Current PG count : $POOL_PG"
# echo " PG per OSD (formula): ($POOL_PG * $POOL_SIZE) / $OSD_COUNT = $PG_PER_OSD"
echo " PG per OSD : $PG_PER_OSD"
echo

elif [[ "$POOL_TYPE" -eq 3 ]]; then
# Erasure-coded pool
# 1) Retrieve the EC profile => get k, m
if [[ -z "$EC_PROFILE" ]]; then
echo "ERROR: EC pool '$POOL_NAME' has no 'erasure_code_profile'!"
continue
fi

get_ec_params "$EC_PROFILE"
K_VAL="${EC_K[$EC_PROFILE]}"
M_VAL="${EC_M[$EC_PROFILE]}"
if [[ -z "$K_VAL" || -z "$M_VAL" ]]; then
echo "ERROR: Could not determine k and m for profile '$EC_PROFILE'!"
continue
fi

# Formula: PG per OSD = (pg_num * (k + m)) / OSD_COUNT
PG_PER_OSD=$(awk -v pg="$POOL_PG" -v k="$K_VAL" -v m="$M_VAL" -v osd="$OSD_COUNT" '
BEGIN {
val = (pg * (k + m)) / osd;
printf "%.2f", val;
}'
)

echo -e "Pool Name: \e[31m$POOL_NAME\e[0m"
echo " Type : Erasure-coded"
# echo " EC profile : $EC_PROFILE"
echo " k + m : $K_VAL + $M_VAL"
echo " Current PG count : $POOL_PG"
# echo " PG per OSD (formula): ($POOL_PG * ($K_VAL + $M_VAL)) / $OSD_COUNT = $PG_PER_OSD"
echo " PG per OSD : $PG_PER_OSD"
echo
else
echo "Pool Name: $POOL_NAME"
echo " Unrecognized type: $POOL_TYPE (not 1, not 3). Skipping."
echo
fi

done

0 comments on commit 9976181

Please sign in to comment.