Skip to content

Instantly share code, notes, and snippets.

@redmcg
Last active May 29, 2024 00:34
Show Gist options
  • Save redmcg/60cfff7bca6f32969188008ad4a44c9a to your computer and use it in GitHub Desktop.
Save redmcg/60cfff7bca6f32969188008ad4a44c9a to your computer and use it in GitHub Desktop.
Bash script to show k8s PVC usage
#!/usr/bin/env bash
NODESAPI=/api/v1/nodes
function getNodes() {
kubectl get --raw $NODESAPI | jq -r '.items[].metadata.name'
}
function getPVCs() {
jq -s '[flatten | .[].pods[].volume[]? | select(has("pvcRef")) | '\
'{name: .pvcRef.name, capacityBytes, usedBytes, availableBytes, '\
'percentageUsed: (.usedBytes / .capacityBytes * 100)}] | sort_by(.name)'
}
function column() {
awk '{ for (i = 1; i <= NF; i++) { d[NR, i] = $i; w[i] = length($i) > w[i] ? length($i) : w[i] } } '\
'END { for (i = 1; i <= NR; i++) { printf("%-*s", w[1], d[i, 1]); for (j = 2; j <= NF; j++ ) { printf("%*s", w[j] + 1, d[i, j]) } print "" } }'
}
function defaultFormat() {
awk 'BEGIN { print "PVC 1K-blocks Used Available Use%" } '\
'{$2 = $2/1024; $3 = $3/1024; $4 = $4/1024; $5 = sprintf("%.0f%%",$5); print $0}'
}
function humanFormat() {
awk 'BEGIN { print "PVC Size Used Avail Use%" } '\
'{$5 = sprintf("%.0f%%",$5); printf("%s ", $1); system(sprintf("numfmt --to=iec %s %s %s | sed '\''N;N;s/\\n/ /g'\'' | tr -d \\\\n", $2, $3, $4)); print " " $5 }'
}
function format() {
jq -r '.[] | "\(.name) \(.capacityBytes) \(.usedBytes) \(.availableBytes) \(.percentageUsed)"' |
$format | column
}
if [ "$1" == "-h" ]; then
format=humanFormat
else
format=defaultFormat
fi
for node in $(getNodes); do
kubectl get --raw $NODESAPI/$node/proxy/stats/summary
done | getPVCs | format
@mattwelke
Copy link

That's neat. That plugin's README says it's only compatible with GKE right now though. This script's approach is just pure Kubernetes, right?

@redmcg
Copy link
Author

redmcg commented Feb 18, 2023

Yeah, I'm using the kubernates rest api. But I took a quick look at the code for kubectl-df-pv, and it looks like it's using the same approach. I couldn't see anything that suggested this script would provide a greater level of support; but testing would confirm.

@vsadanala
Copy link

vsadanala commented Mar 26, 2023

@redmcg
I have managed to add namespace column to your existing code

kubectl get --raw $NODESAPI/$node/proxy/stats/summary|jq -s '[flatten | .[].pods[].volume[]? | select(has("pvcRef")) | ''{namespace: .pvcRef.namespace, name: .pvcRef.name, capacityBytes, usedBytes, availableBytes, ''percentageUsed: (.usedBytes / .capacityBytes * 100)}] | sort_by(.namespace)'|jq -r '.[] | "(.namespace) (.name) (.capacityBytes) (.usedBytes) (.availableBytes) (.percentageUsed)"'|awk '{$3 = $3/(102410241024); $4 = $4/(10241024); $5= $5/(10241024*1024); $6 = sprintf("%.0f%%",$6); print $0}'


Namsespace PVC Capacity Used Available Used%

Thank you @redmcg

@redmcg
Copy link
Author

redmcg commented Mar 27, 2023

Good work @vsadanala ! And thanks for sharing.

@dandvc
Copy link

dandvc commented Jul 18, 2023

Nice Work ! It's very useful !! TKS
image

@thibault-ketterer
Copy link

thibault-ketterer commented Feb 7, 2024

nice ! thanks

I would had this > 50% usage

bash kubedf -h |tr -d '%' |awk '$NF > 50' | sed -e 's/$/%/'

@hamardk
Copy link

hamardk commented May 29, 2024

Hi,
I just added an option to list the pvc information filtered with a namespace based on the script above:

#!/usr/bin/env bash

function getNodes() {
kubectl get --raw=/api/v1/nodes | jq -r '.items[].metadata.name'
}

function getPVCs() {
jq -s '[flatten | .[].pods[].volume[]? | select(has("pvcRef")) | '
'{namespace: .pvcRef.namespace, name: .pvcRef.name, capacityBytes, usedBytes, availableBytes, '
'percentageUsed: (.usedBytes / .capacityBytes * 100)}] | sort_by(.namespace)'
}

function column() {
awk '{ for (i = 1; i <= NF; i++) { d[NR, i] = $i; w[i] = length($i) > w[i] ? length($i) : w[i] } } '
'END { for (i = 1; i <= NR; i++) { printf("%-*s", w[1], d[i, 1]); for (j = 2; j <= NF; j++ ) { printf("%*s", w[j] + 1, d[i, j]) } print "" } }'
}

function defaultFormat() {
awk 'BEGIN { print "Namespace PVC 1K-blocks Used Available Use%" } '
'{$3 = $3/1024; $4 = $4/1024; $5 = $5/1024; $6 = sprintf("%.0f%%",$6); print $0}'
}

function humanFormat() {
awk 'BEGIN { print "Namespace PVC Size Used Avail Use%" } '
'{$6 = sprintf("%.0f%%",$6); printf("%s ", $1); printf("%s ", $2); system(sprintf("numfmt --to=iec %s %s %s | sed '''N;N;s/\n/ /g''' | tr -d \\n", $3, $4, $5)); print " " $6 }'
}

function format() {
jq '.[] | "(.namespace) (.name) (.capacityBytes) (.usedBytes) (.availableBytes) (.percentageUsed)"' |
sed 's/^"|"$//g' |
$format | column
}

function get_pvc_info(){
local _format=${1:-h} && shift
local namespace=${1:-""}
format=humanFormat

[[ "${_format,,}" != "h" ]] && format=defaultFormat

table=$(for node in $(getNodes); do
kubectl get --raw=/api/v1/nodes/${node}/proxy/stats/summary
done | getPVCs | format)
header=$(echo -e "${table}" | head -1)
echo -e "${header}"
[[ -n "${namespace}" ]] && echo -e "${table}" | grep -w "^${namespace} " || echo -e "${table}"
}

get_pvc_info "$@"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment