+++ /dev/null
-#!/bin/bash
-#
-# ceph-lazy : Be efficient, be lazy !
-#
-# Author: Gregory Charot <gcharot@redhat.com>
-#
-# This is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-
-# Specify exta option for ceph like the username/keyring/etc. Can also be done with CEPH_ARGS global variable
-#CEPH_OPT="-n client.username"
-VERSION="1.1.2"
-
-#
-# Print info message to stderr
-#
-
-function echoinfo() {
- printf "INFO: %s\n" "$*" >&2;
-}
-
-
-#
-# Print error message to stderr
-#
-
-function echoerr() {
- printf "ERROR: %s\n" "$*" >&2;
-}
-
-
-function help() {
- >&2 echo "Usage : ceph-lazy [-d | -h] [command] [parameters]
-
-Ceph complex quering tool - Version $VERSION
-
-OPTIONS
-========
- -d Activate debug mode
- -h Print help
-
-COMMANDS
-=========
-
- Host
- -----
- host-get-osd hostname List all OSD IDs attached to a particular node.
- host-get-nodes List all storage nodes.
- host-osd-usage hostname Show total OSD space usage of a particular node (-d for details).
- host-all-usage Show total OSD space usage of each nodes (-d for details)
-
- Placement groups
- -----------------
- pg-get-host pgid Find PG storage hosts (first is primary)
- pg-most-write Find most written PG (nb operations)
- pg-less-write Find less written PG (nb operations)
- pg-most-write-kb Find most written PG (data written)
- pg-less-write-kb Find less written PG (data written)
- pg-most-read Find most read PG (nb operations)
- pg-less-read Find less read PG (nb operations)
- pg-most-read-kb Find most read PG (data read)
- pg-less-read-kb Find less read PG (data read)
- pg-empty Find empty PGs (no stored object)
-
- RBD
- ----
- rbd-prefix pool_name image_name Return RBD image prefix
- rbd-count pool_name image_name Count number of objects in a RBD image
- rbd-host pool_name image_name Find RBD primary storage hosts
- rbd-osd pool_name image_name Find RBD primary OSDs
- rbd-size pool_name image_name Print RBD image real size
- rbd-all-size pool_name Print all RBD images size (Top first)
-
- OSD
- ----
- osd-most-used Show the most used OSD (capacity)
- osd-less-used Show the less used OSD (capacity)
- osd-get-ppg osd_id Show all primaries PGS hosted on a OSD
- osd-get-pg osd_id Show all PGS hosted on a OSD
-
- Objects
- --------
- object-get-host pool_name object_id Find object storage hosts (first is primary)
- "
-
-}
-
-#
-# Check dependencies
-#
-function check_requirements()
-{
-
- # List of command dependencies
- local bin_dep="ceph rados rbd osdmaptool jq"
-
- for cmd in $bin_dep; do
- [ $DEBUG -eq 1 ] && echoinfo "Checking for $cmd..."
- $cmd --version >/dev/null 2>&1 || { echoerr "$cmd cannot be found... Aborting."; return 1; }
- done
-
- CEPH="ceph $CEPH_OPT"
-
- [ $DEBUG -eq 1 ] && echoinfo "Checking Ceph connectivity & basic permissions..."
-
- if ! $CEPH -s &> /dev/null; then
- echoerr "Cannot connect to cluster, please check your username & permissions"
- echoerr "Command $CEPH -s failed"
- return 1
- fi
-
- JQ="jq -M --raw-output"
-}
-
-#
-# Print the host that hosts a specific PG
-#
-function find_host_from_pg() {
-
- if [ $# -eq 1 ]; then
- local PGID=$1
- else
- echoerr "This command requires one argument"
- help
- exit 1
- fi
-
- [ $DEBUG -eq 1 ] && echoinfo "PG $PGID has been found at (first is primary) : "
-
- for osd in $($CEPH pg $PGID query | $JQ -cr .up[]); do
- echo -n "OSD:osd.$osd | Host:"
- $CEPH osd find $osd --format json 2> /dev/null | $JQ .crush_location.host
- done
-}
-
-
-#
-# Print the host that hosts a specific object
-#
-function find_host_from_object() {
-
- if [ $# -eq 2 ]; then
- local pool=$1
- local objid=$2
- else
- echoerr "This command requires two arguments"
- help
- exit 1
- fi
-
- local pgid=$($CEPH osd map $pool $objid --format json 2> /dev/null | $JQ -cr .pgid)
-
- [ $DEBUG -eq 1 ] && echoinfo $objid found into PG $pgid
-
- while read host; do
- echo "PG:$pgid | $host"
- done < <(find_host_from_pg $pgid)
-}
-
-
-#
-# Print all primary pgs hosted by an OSD
-#
-function find_prim_pg_from_osd() {
-
- if [ $# -eq 1 ]; then
- local posd=$1
- else
- echoerr "This command requires one argument"
- help
- exit 1
- fi
-
- [ $DEBUG -eq 1 ] && echoinfo "Looking for primary PGs beloging to OSD $posd"
- $CEPH pg dump pgs --format json 2>/dev/null | $JQ --argjson posd $posd '.[] | select(.acting_primary==$posd).pgid'
-}
-
-
-#
-# Print all pgs (primay & secondary) hosted by an OSD
-#
-function find_all_pg_from_osd() {
-
- if [ $# -eq 1 ]; then
- local osd=$1
- else
- echoerr "This command requires one argument"
- help
- exit 1
- fi
-
- [ $DEBUG -eq 1 ] && echoinfo "Looking for all PGs mapped to OSD $osd"
- $CEPH pg dump pgs --format json 2> /dev/null | $JQ -M --argjson osd $osd '.[] | select(.up[]==$osd).pgid'
-}
-
-
-#
-# Check if a given image exists
-#
-function check_rbd_exists(){
-
- pool=$1
- rbd=$2
-
- if ! rbd info -p $pool $rbd &> /dev/null; then
- echoerr "Unable to find image $pool/$rbd"
- exit 1
- fi
-}
-
-
-#
-# Return RBD prefix from image name
-#
-function get_rbd_prefix() {
-
- if [ $# -eq 2 ]; then
- local pool=$1
- local rbd=$2
- else
- echoerr "This command requires two arguments"
- help
- exit 1
- fi
-
- check_rbd_exists $pool $rbd
-
- local prefix=$(rbd --image $rbd -p $pool info --format json 2> /dev/null | jq --raw-output .block_name_prefix)
- if [ -z $prefix ]; then
- echoerr "Unable to find RBD Prefix for image $pool/$rbd"
- exit 1
- else
- echo $prefix
- fi
-
-}
-
-
-#
-# Count number of object in a RBD image
-#
-function count_rbd_object() {
-
- if [ $# -eq 2 ]; then
- local pool=$1
- local rbd=$2
- else
- echoerr "This command requires two arguments"
- help
- exit 1
- fi
-
- check_rbd_exists $pool $rbd
-
- local rbd_prefix=$(get_rbd_prefix $pool $rbd)
-
- [ $DEBUG -eq 1 ] && echoinfo "RBD image $pool/$rbd has prefix $rbd_prefix; now couning objects..."
-
- local nb_obj=$(rados -p $pool ls | grep $rbd_prefix | wc -l)
-
- [ $DEBUG -eq 1 ] && echoinfo "RBD image $pool/$rbd has $nb_obj objects"
- echo $nb_obj
-}
-
-
-#
-# Find primary storage host for a given RBD image
-#
-function find_prim_host_from_rbd() {
-
- if [ $# -eq 2 ]; then
- local pool=$1
- local rbd=$2
- else
- echoerr "This command requires two arguments"
- help
- exit 1
- fi
-
- check_rbd_exists $pool $rbd
-
- local osd="null"
- local osdmap_t=$(mktemp)
- local osdtree_t=$(mktemp)
- # Get RBD image prefix
- local rbd_prefix=$(get_rbd_prefix $pool $rbd)
-# Exit if we received an empty prefix
- [ -z $rbd_prefix ] && exit 1
-
-# Get pool ID from pool name
- local pool_id=$(ceph osd lspools -f json | $JQ -M --arg pool $pool '.[]|select(.poolname==$pool).poolnum')
-
- [ $DEBUG -eq 1 ] && echoinfo "RBD image $pool/$rbd has prefix $rbd_prefix; now finding primary host..."
-
- [ $DEBUG -eq 1 ] && echoinfo "Dumping OSD map to $osdmap_t"
- if ! $CEPH osd getmap > $osdmap_t 2> /dev/null; then
- echoerr "Failed to retrieve OSD map"
- exit 1
- fi
-
- [ $DEBUG -eq 1 ] && echoinfo "Dumping OSD tree to $osdtree_t"
-
- if ! $CEPH osd tree --format json > $osdtree_t; then
- echoerr "Failed to retrieve OSD tree"
- exit 1
- fi
-
- [ $DEBUG -eq 1 ] && echoinfo "Looking for hosts..."
-
-# For each object in the RBD image
- for obj in $(rados -p $pool ls | grep $rbd_prefix);
- do
-# Map object to osd. osdmaptoot does not support json output so using dirty sed.
- osd=$(osdmaptool --test-map-object $obj --pool $pool_id $osdmap_t 2>/dev/null | sed -r 's/.*\[([[:digit:]]+),.*/\1/' | grep -v osdmaptool)
-# Map osd to host
- $JQ --argjson osd $osd '.nodes[] | select(.type=="host") | select(.children[] == $osd).name' $osdtree_t
- done | sort -u
-
-# Cleaning files
- rm -f $osdtree_t $osdmap_t
-}
-
-
-#
-# Find primary OSDs for a given RBD image
-#
-function find_prim_osd_from_rbd() {
-
- if [ $# -eq 2 ]; then
- local pool=$1
- local rbd=$2
- else
- echoerr "This command requires two arguments"
- help
- exit 1
- fi
-
- check_rbd_exists $pool $rbd
-
- local osd="null"
- local osdmap_t=$(mktemp)
- local osdtree_t=$(mktemp)
- # Get RBD image prefix
- local rbd_prefix=$(get_rbd_prefix $pool $rbd)
-
-# Exit if we received an empty prefix
- [ -z $rbd_prefix ] && exit 1
-
- [ $DEBUG -eq 1 ] && echoinfo "RBD image $pool/$rbd has prefix $rbd_prefix; now finding primary OSDs..."
-
- [ $DEBUG -eq 1 ] && echoinfo "Dumping OSD map to $osdmap_t"
- if ! $CEPH osd getmap > $osdmap_t; then
- echoerr "Failed to retrieve OSD map"
- exit 1
- fi
-
-# For each object in the RBD image
- for obj in $(rados -p $pool ls | grep $rbd_prefix);
- do
-# Map object to osd. osdmaptoot does not support json output so using dirty sed.
- osd=$(osdmaptool --test-map-object $obj $osdmap_t 2>/dev/null | sed -r 's/.*\[([[:digit:]]+),.*/\1/' | grep -v osdmaptool)
- echo "osd.${osd}"
- done | sort -u
-
-# Cleaning files
- rm -f $osdmap_t
-}
-
-
-#
-# Print RBD image real size - Source http://ceph.com/planet/real-size-of-a-ceph-rbd-image/
-#
-
-function print_rbd_real_size {
-
- if [ $# -eq 2 ]; then
- local pool=$1
- local rbd=$2
- else
- echoerr "This command requires two arguments"
- help
- exit 1
- fi
-
- [ $DEBUG -eq 1 ] && echoinfo "Checking if RBD image exists..."
-
- check_rbd_exists $pool $rbd
-
- rbd diff $pool/$rbd | awk '{ SUM += $2 } END { print SUM/1024/1024 " MB" }'
-
-}
-
-
-#
-# Print all RBD image real sizes - Top first
-#
-
-function list_all_rbd_real_size {
-
- if [ $# -eq 1 ]; then
- local pool=$1
- else
- echoerr "This command requires one argument"
- help
- exit 1
- fi
-
- [ $DEBUG -eq 1 ] && echoinfo "Looking for RBD images in pool $pool"
-
- while read rbd; do
- [ $DEBUG -eq 1 ] && echoinfo "Inspecting image $rbd"
- rbd diff $pool/$rbd | awk -v rbd="$rbd" '{ SUM += $2 } END { print SUM/1024/1024 " MB - " rbd }'
- done < <(rbd -p $pool ls) | sort -rV
-}
-
-
-#
-# Print OSDs belonging to a particular storage host
-#
-
-function list_osd_from_host() {
-
- if [ $# -eq 1 ]; then
- local host=$1
- else
- echoerr "This command requires one argument"
- help
- exit 1
- fi
-
- $CEPH osd tree --format json-pretty 2> /dev/null | $JQ --arg host $host '.nodes[] | select(.type=="host") | select(.name == $host).children[]' | sort -V
-
-}
-
-
-#
-# List all OSD nodes
-#
-
-function list_all_nodes() {
-
-
- $CEPH osd tree --format json | $JQ -M --raw-output '.nodes[] | select(.type=="host") | .name' | sort -V
-
-}
-
-
-#
-# Print Total OSD usage of a particular storage host
-#
-
-function show_host_osd_usage() {
-
- if [ $# -eq 1 ]; then
- local host=$1
- else
- echoerr "This command requires one argument"
- help
- exit 1
- fi
-
- local pgmap_t=$(mktemp)
-
- local osd_used_kb=0
- local total_used_kb=0
-
- local total_available_kb=0
- local osd_available_kb=0
-
- local total_size_kb=0
- local osd_size_kb=0
- local nb_osd=0
-
- [ $DEBUG -eq 1 ] && echoinfo "Dumping PG map..."
- if ! $CEPH pg dump osds --format json 2>/dev/null > $pgmap_t; then
- echoerr "Failed to retrieve PG map"
- exit 1
- fi
-
- [ $DEBUG -eq 1 ] && echoinfo "Looking for all OSDs on host $host..."
-
- for osd in $(list_osd_from_host $host); do
-
- osd_used_kb=$($JQ --argjson osd $osd '.[] | select(.osd == $osd).kb_used' $pgmap_t)
- osd_available_kb=$($JQ --argjson osd $osd '.[] | select(.osd == $osd).kb_avail' $pgmap_t)
- osd_size_kb=$($JQ --argjson osd $osd '.[] | select(.osd == $osd).kb' $pgmap_t)
-
- [ $DEBUG -eq 1 ] && echoinfo "OSD:$osd | Size:$(echo "scale=1;$osd_size_kb/1024/1024" | bc -l)GB | Used:$(echo "scale=1;$osd_used_kb /1024/1024" | bc -l)GB | Available:$(echo "scale=1;$osd_available_kb/1024/1024" | bc -l)GB"
-
- let "total_used_kb=total_used_kb+osd_used_kb"
- let "total_available_kb=total_available_kb+osd_available_kb"
- let "total_size_kb=total_size_kb+osd_size_kb"
- let "nb_osd++"
-
- done
-
- echo "Host:$host | OSDs:$nb_osd | Total_Size:$(echo "scale=1;$total_size_kb/1024/1024" | bc -l)GB | Total_Used:$(echo "scale=1;$total_used_kb /1024/1024" | bc -l)GB | Total_Available:$(echo "scale=1;$total_available_kb/1024/1024" | bc -l)GB"
-
- rm -f $pgmap_t
-}
-
-
-#
-# Print Total OSD usage of all nodes
-#
-
-function list_all_nodes_osd_usage() {
-
-
- for host in $(list_all_nodes); do
-
- [ $DEBUG -eq 1 ] && echoinfo "Looking at node $host..."
-
- show_host_osd_usage $host
- done
-
-}
-
-
-#
-# Find most used (space) OSD
-#
-
-function find_most_used_osd() {
-
- local osd=$($CEPH pg dump osds --format json 2> /dev/null| $JQ 'max_by(.kb_used) | .osd')
- local host=$($CEPH osd find $osd 2> /dev/null | $JQ .crush_location.host)
-
- echo "OSD:osd.${osd} | host:$host"
-}
-
-
-#
-# Find less used (space) OSD
-#
-
-function find_less_used_osd() {
-
- local osd=$($CEPH pg dump osds --format json 2> /dev/null| $JQ 'min_by(.kb_used) | .osd')
- local host=$($CEPH osd find $osd 2> /dev/null | $JQ .crush_location.host)
-
- echo "OSD:osd.${osd} | host:$host"
-}
-
-
-#
-# Query PG stats
-#
-
-function pg_stat_query() {
-
- if [ $# -eq 1 ]; then
- local query_type=$1
- else
- echoerr "This command requires one argument"
- help
- exit 1
- fi
-
- local pgmap_t=$(mktemp)
-
- [ $DEBUG -eq 1 ] && echoinfo "Dumping PG map..."
- if ! $CEPH pg dump pgs --format json 2>/dev/null > $pgmap_t; then
- echoerr "Failed to retrieve PG map"
- exit 1
- fi
-
- local pgid=$($JQ --arg query_type $query_type "$query_type" $pgmap_t)
- [ $DEBUG -eq 1 ] && echoinfo "Found PGID $pgid"
-
- local osd=$($JQ --arg pgid $pgid '.[] | select(.pgid == $pgid).acting_primary' $pgmap_t)
- [ $DEBUG -eq 1 ] && echoinfo "Found OSD $osd"
-
- local host=$($CEPH osd find $osd --format json 2> /dev/null | $JQ .crush_location.host)
- [ $DEBUG -eq 1 ] && echoinfo "Found host $host"
-
- echo "PG:$pgid | OSD:osd.$osd | Host:$host"
-
- rm -f $pgmap_t
-}
-
-
-#
-# Find empty pgs (no object stored)
-#
-
-function find_empty_pg() {
-
- $CEPH pg dump pgs --format json 2>/dev/null | $JQ '.[] | select(.stat_sum.num_objects == 0).pgid'
-
-}
-
-
-#
-# MAIN
-#
-
-
-# Print help if no argument is given
-if [ $# -eq 0 ]; then
- help
- exit 1
-fi
-
-# Activate debug mode if -d is specified as first parameter
-if [ "$1" = "-d" ]; then
- echoinfo "Debug mode activated"
- DEBUG=1
- shift
-else
- DEBUG=0
-fi
-
-
-# Check if all requirements are met
-check_requirements || exit 1
-
-
-# Call proper function
-case $1 in
- "-h")
- help
- exit 0
- ;;
- "host-get-osd")
- list_osd_from_host $2
- ;;
- "host-get-nodes")
- list_all_nodes
- ;;
- "host-osd-usage")
- show_host_osd_usage $2
- ;;
- "host-all-usage")
- list_all_nodes_osd_usage
- ;;
- "pg-get-host")
- find_host_from_pg $2
- ;;
- "pg-most-write")
- pg_stat_query "max_by(.stat_sum.num_write).pgid"
- ;;
- "pg-less-write")
- pg_stat_query "min_by(.stat_sum.num_write).pgid"
- ;;
- "pg-most-write-kb")
- pg_stat_query "max_by(.stat_sum.num_write_kb).pgid"
- ;;
- "pg-less-write-kb")
- pg_stat_query "min_by(.stat_sum.num_write_kb).pgid"
- ;;
- "pg-most-read")
- pg_stat_query "max_by(.stat_sum.num_read).pgid"
- ;;
- "pg-less-read")
- pg_stat_query "min_by(.stat_sum.num_read).pgid"
- ;;
- "pg-most-read-kb")
- pg_stat_query "max_by(.stat_sum.num_read_kb).pgid"
- ;;
- "pg-less-read-kb")
- pg_stat_query "min_by(.stat_sum.num_read_kb).pgid"
- ;;
- "rbd-prefix")
- get_rbd_prefix $2 $3
- ;;
- "rbd-count")
- count_rbd_object $2 $3
- ;;
- "rbd-host")
- find_prim_host_from_rbd $2 $3
- ;;
- "rbd-osd")
- find_prim_osd_from_rbd $2 $3
- ;;
- "rbd-size")
- print_rbd_real_size $2 $3
- ;;
- "rbd-all-size")
- list_all_rbd_real_size $2
- ;;
- "osd-most-used")
- find_most_used_osd
- ;;
- "osd-less-used")
- find_less_used_osd
- ;;
- "osd-get-ppg")
- find_prim_pg_from_osd $2
- ;;
- "osd-get-pg")
- find_all_pg_from_osd $2
- ;;
- "pg-empty")
- find_empty_pg
- ;;
- "object-get-host")
- find_host_from_object $2 $3
- ;;
- *)
- echoerr "Unknown command : $1"
- help
- exit 1
- ;;
-esac
-