fixed the ram script
This commit is contained in:
190
show-ram.sh
190
show-ram.sh
@@ -5,54 +5,104 @@
|
|||||||
# Without argument: shows RAM per node and total server RAM
|
# Without argument: shows RAM per node and total server RAM
|
||||||
# With argument: shows containers for specific node
|
# With argument: shows containers for specific node
|
||||||
|
|
||||||
BASEPATH="$(dirname "$0")"
|
set -euo pipefail
|
||||||
source $BASEPATH/.env
|
|
||||||
|
|
||||||
NODE_PATH="$1"
|
BASEPATH="$(dirname "$0")"
|
||||||
|
source "$BASEPATH/.env"
|
||||||
|
|
||||||
|
NODE_PATH="${1:-}"
|
||||||
|
|
||||||
# Function to convert memory string to MiB
|
# Function to convert memory string to MiB
|
||||||
to_mib() {
|
to_mib() {
|
||||||
local val="$1"
|
local val="$1"
|
||||||
local num=$(echo "$val" | sed 's/[^0-9.]//g')
|
local num=$(echo "$val" | sed 's/[^0-9.]//g')
|
||||||
|
if [ -z "$num" ] || [ "$num" = "0" ]; then
|
||||||
|
echo "0"
|
||||||
|
return
|
||||||
|
fi
|
||||||
if echo "$val" | grep -qi "GiB"; then
|
if echo "$val" | grep -qi "GiB"; then
|
||||||
echo "$num * 1024" | bc
|
echo "$num * 1024" | bc -l | awk '{printf "%.2f", $1}'
|
||||||
elif echo "$val" | grep -qi "MiB"; then
|
elif echo "$val" | grep -qi "MiB"; then
|
||||||
echo "$num"
|
echo "$num" | awk '{printf "%.2f", $1}'
|
||||||
elif echo "$val" | grep -qi "KiB"; then
|
elif echo "$val" | grep -qi "KiB"; then
|
||||||
echo "$num / 1024" | bc
|
echo "$num / 1024" | bc -l | awk '{printf "%.2f", $1}'
|
||||||
else
|
else
|
||||||
echo "$num"
|
echo "$num" | awk '{printf "%.2f", $1}'
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to format MiB to human readable
|
# Function to format MiB to human readable
|
||||||
format_size() {
|
format_size() {
|
||||||
local mib="$1"
|
local mib="$1"
|
||||||
if [ "${mib%.*}" -ge 1024 ] 2>/dev/null; then
|
# Handle empty or zero values
|
||||||
echo "scale=2; $mib / 1024" | bc | xargs printf "%.2f GiB"
|
if [ -z "$mib" ] || [ "$mib" = "0" ] || [ "$mib" = "0.00" ]; then
|
||||||
|
echo "0 MiB"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
# Compare as float using awk
|
||||||
|
if awk "BEGIN {exit !($mib >= 1024)}"; then
|
||||||
|
echo "scale=2; $mib / 1024" | bc -l | xargs printf "%.2f GiB"
|
||||||
else
|
else
|
||||||
printf "%.0f MiB" "$mib"
|
printf "%.0f MiB" "$mib"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Cache for docker stats (container_id -> mem_usage)
|
||||||
|
declare -A DOCKER_STATS_CACHE
|
||||||
|
|
||||||
|
# Cache for service -> container_id mapping
|
||||||
|
declare -A SERVICE_TO_CID
|
||||||
|
|
||||||
|
# Initialize caches - fetch all container stats once
|
||||||
|
init_docker_caches() {
|
||||||
|
# Get all running container IDs with their service labels
|
||||||
|
while IFS=$'\t' read -r cid service; do
|
||||||
|
[ -z "$cid" ] && continue
|
||||||
|
if [ -n "$service" ]; then
|
||||||
|
SERVICE_TO_CID["$service"]="$cid"
|
||||||
|
fi
|
||||||
|
done < <(docker ps --format "{{.ID}}\t{{.Label \"com.docker.compose.service\"}}" 2>/dev/null || true)
|
||||||
|
|
||||||
|
# Get stats for all containers at once (much faster than individual calls)
|
||||||
|
# docker stats can take multiple container IDs, but we'll get all stats in one call
|
||||||
|
if [ ${#SERVICE_TO_CID[@]} -gt 0 ]; then
|
||||||
|
local all_cids=($(printf '%s\n' "${SERVICE_TO_CID[@]}" | sort -u))
|
||||||
|
if [ ${#all_cids[@]} -gt 0 ]; then
|
||||||
|
# Call docker stats once with all container IDs
|
||||||
|
while IFS=$'\t' read -r cid mem_usage; do
|
||||||
|
[ -z "$cid" ] && continue
|
||||||
|
DOCKER_STATS_CACHE["$cid"]="$mem_usage"
|
||||||
|
done < <(docker stats --no-stream --format "{{.ID}}\t{{.MemUsage}}" "${all_cids[@]}" 2>/dev/null || true)
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# Function to get RAM for a compose file by matching service names
|
# Function to get RAM for a compose file by matching service names
|
||||||
get_compose_ram() {
|
get_compose_ram() {
|
||||||
local compose_file="$1"
|
local compose_file="$1"
|
||||||
local total=0
|
local total=0
|
||||||
|
|
||||||
# Get service names defined in this compose file
|
# Get service names defined in this compose file
|
||||||
services=$(cat "$compose_file" | yaml2json - 2>/dev/null | jq -r '.services | keys[]' 2>/dev/null)
|
local services
|
||||||
|
services=$(cat "$compose_file" 2>/dev/null | yaml2json - 2>/dev/null | jq -r '.services | keys[]' 2>/dev/null || echo "")
|
||||||
[ -z "$services" ] && echo "0" && return
|
[ -z "$services" ] && echo "0" && return
|
||||||
|
|
||||||
for service in $services; do
|
for service in $services; do
|
||||||
# Find container by service label
|
# Use cached container ID
|
||||||
cid=$(docker ps -q --filter "label=com.docker.compose.service=$service" 2>/dev/null)
|
local cid="${SERVICE_TO_CID[$service]:-}"
|
||||||
[ -z "$cid" ] && continue
|
[ -z "$cid" ] && continue
|
||||||
|
|
||||||
mem_usage=$(docker stats --no-stream --format "{{.MemUsage}}" "$cid" 2>/dev/null | awk -F'/' '{print $1}')
|
# Use cached memory usage
|
||||||
|
local mem_usage="${DOCKER_STATS_CACHE[$cid]:-}"
|
||||||
[ -z "$mem_usage" ] && continue
|
[ -z "$mem_usage" ] && continue
|
||||||
|
|
||||||
|
# Extract just the used memory (before the /)
|
||||||
|
mem_usage=$(echo "$mem_usage" | awk -F'/' '{print $1}' | xargs)
|
||||||
|
[ -z "$mem_usage" ] && continue
|
||||||
|
|
||||||
|
local mem_mib
|
||||||
mem_mib=$(to_mib "$mem_usage")
|
mem_mib=$(to_mib "$mem_usage")
|
||||||
total=$(echo "$total + $mem_mib" | bc)
|
total=$(echo "$total + $mem_mib" | bc -l | awk '{printf "%.2f", $1}')
|
||||||
done
|
done
|
||||||
|
|
||||||
echo "$total"
|
echo "$total"
|
||||||
@@ -76,11 +126,31 @@ if [ -z "$NODE_PATH" ]; then
|
|||||||
echo "RAM usage per node:"
|
echo "RAM usage per node:"
|
||||||
echo "========================================"
|
echo "========================================"
|
||||||
|
|
||||||
|
# Initialize caches once - this batches all docker calls
|
||||||
|
init_docker_caches
|
||||||
|
|
||||||
IFS=':' read -ra parts <<< "$COMPOSE_FILE"
|
IFS=':' read -ra parts <<< "$COMPOSE_FILE"
|
||||||
|
|
||||||
declare -A node_ram
|
declare -A node_ram
|
||||||
total_mib=0
|
total_mib=0
|
||||||
|
|
||||||
|
# Export caches to temp files for parallel processing
|
||||||
|
temp_dir=$(mktemp -d)
|
||||||
|
trap "rm -rf $temp_dir" EXIT
|
||||||
|
|
||||||
|
# Write service->cid mapping to file
|
||||||
|
for service in "${!SERVICE_TO_CID[@]}"; do
|
||||||
|
echo "$service|${SERVICE_TO_CID[$service]}" >> "$temp_dir/service_cid.map"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Write cid->mem_usage mapping to file
|
||||||
|
for cid in "${!DOCKER_STATS_CACHE[@]}"; do
|
||||||
|
echo "$cid|${DOCKER_STATS_CACHE[$cid]}" >> "$temp_dir/cid_mem.map"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Process nodes in parallel using background jobs
|
||||||
|
pids=()
|
||||||
|
|
||||||
for part in "${parts[@]}"; do
|
for part in "${parts[@]}"; do
|
||||||
# Skip blacklisted files
|
# Skip blacklisted files
|
||||||
is_blacklisted "$part" && continue
|
is_blacklisted "$part" && continue
|
||||||
@@ -91,15 +161,65 @@ if [ -z "$NODE_PATH" ]; then
|
|||||||
# Get node path (remove .yml extension)
|
# Get node path (remove .yml extension)
|
||||||
node_path="${part%.yml}"
|
node_path="${part%.yml}"
|
||||||
|
|
||||||
# Get RAM usage
|
# Process in background for parallel execution
|
||||||
ram_mib=$(get_compose_ram "$compose_file")
|
(
|
||||||
[ "$ram_mib" = "0" ] && continue
|
# Rebuild caches in this subprocess from temp files
|
||||||
|
declare -A local_service_cid
|
||||||
|
declare -A local_cid_mem
|
||||||
|
|
||||||
node_ram["$node_path"]="$ram_mib"
|
while IFS='|' read -r service cid; do
|
||||||
total_mib=$(echo "$total_mib + $ram_mib" | bc)
|
[ -n "$service" ] && [ -n "$cid" ] && local_service_cid["$service"]="$cid"
|
||||||
|
done < "$temp_dir/service_cid.map" 2>/dev/null || true
|
||||||
|
|
||||||
|
while IFS='|' read -r cid mem; do
|
||||||
|
[ -n "$cid" ] && [ -n "$mem" ] && local_cid_mem["$cid"]="$mem"
|
||||||
|
done < "$temp_dir/cid_mem.map" 2>/dev/null || true
|
||||||
|
|
||||||
|
# Get service names from compose file
|
||||||
|
services=$(cat "$compose_file" 2>/dev/null | yaml2json - 2>/dev/null | jq -r '.services | keys[]' 2>/dev/null || echo "")
|
||||||
|
[ -z "$services" ] && exit 0
|
||||||
|
|
||||||
|
total=0
|
||||||
|
for service in $services; do
|
||||||
|
cid="${local_service_cid[$service]:-}"
|
||||||
|
[ -z "$cid" ] && continue
|
||||||
|
|
||||||
|
mem_usage="${local_cid_mem[$cid]:-}"
|
||||||
|
[ -z "$mem_usage" ] && continue
|
||||||
|
|
||||||
|
mem_usage=$(echo "$mem_usage" | awk -F'/' '{print $1}' | xargs)
|
||||||
|
[ -z "$mem_usage" ] && continue
|
||||||
|
|
||||||
|
mem_mib=$(to_mib "$mem_usage")
|
||||||
|
total=$(echo "$total + $mem_mib" | bc -l | awk '{printf "%.2f", $1}')
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$total" != "0" ]; then
|
||||||
|
# Sanitize node_path for use as filename (replace / with _)
|
||||||
|
safe_node_path=$(echo "$node_path" | tr '/' '_')
|
||||||
|
echo "$total|$node_path" > "$temp_dir/result_$safe_node_path"
|
||||||
|
fi
|
||||||
|
) &
|
||||||
|
pids+=($!)
|
||||||
done
|
done
|
||||||
|
|
||||||
if [ ${#node_ram[@]} -eq 0 ]; then
|
# Wait for all background jobs to complete
|
||||||
|
for pid in "${pids[@]}"; do
|
||||||
|
wait "$pid" 2>/dev/null || true
|
||||||
|
done
|
||||||
|
|
||||||
|
# Collect results
|
||||||
|
result_count=0
|
||||||
|
for result_file in "$temp_dir"/result_*; do
|
||||||
|
[ -f "$result_file" ] || continue
|
||||||
|
IFS='|' read -r ram_mib node_path < "$result_file"
|
||||||
|
[ -z "$ram_mib" ] || [ "$ram_mib" = "0" ] && continue
|
||||||
|
node_ram["$node_path"]="$ram_mib"
|
||||||
|
total_mib=$(echo "$total_mib + $ram_mib" | bc -l | awk '{printf "%.2f", $1}')
|
||||||
|
result_count=$((result_count + 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$result_count" -eq 0 ]; then
|
||||||
echo "No running nodes found"
|
echo "No running nodes found"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
@@ -107,7 +227,7 @@ if [ -z "$NODE_PATH" ]; then
|
|||||||
# Sort by RAM usage and display
|
# Sort by RAM usage and display
|
||||||
for node_path in "${!node_ram[@]}"; do
|
for node_path in "${!node_ram[@]}"; do
|
||||||
echo "${node_ram[$node_path]} $node_path"
|
echo "${node_ram[$node_path]} $node_path"
|
||||||
done | sort -rn | while read mib name; do
|
done | sort -rn | while IFS=' ' read -r mib name; do
|
||||||
printf "%-55s %s\n" "$name" "$(format_size $mib)"
|
printf "%-55s %s\n" "$name" "$(format_size $mib)"
|
||||||
done
|
done
|
||||||
|
|
||||||
@@ -127,8 +247,11 @@ else
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Initialize caches once
|
||||||
|
init_docker_caches
|
||||||
|
|
||||||
# Get service names from compose file
|
# Get service names from compose file
|
||||||
services=$(cat "$COMPOSE_FILE_PATH" | yaml2json - 2>/dev/null | jq -r '.services | keys[]' 2>/dev/null)
|
services=$(cat "$COMPOSE_FILE_PATH" 2>/dev/null | yaml2json - 2>/dev/null | jq -r '.services | keys[]' 2>/dev/null || echo "")
|
||||||
|
|
||||||
if [ -z "$services" ]; then
|
if [ -z "$services" ]; then
|
||||||
echo "No services found in $NODE_PATH"
|
echo "No services found in $NODE_PATH"
|
||||||
@@ -140,17 +263,30 @@ else
|
|||||||
|
|
||||||
total_mib=0
|
total_mib=0
|
||||||
for service in $services; do
|
for service in $services; do
|
||||||
cid=$(docker ps -q --filter "label=com.docker.compose.service=$service" 2>/dev/null)
|
# Use cached container ID
|
||||||
|
cid="${SERVICE_TO_CID[$service]:-}"
|
||||||
[ -z "$cid" ] && continue
|
[ -z "$cid" ] && continue
|
||||||
|
|
||||||
mem_info=$(docker stats --no-stream --format "{{.MemUsage}}\t{{.MemPerc}}" "$cid" 2>/dev/null)
|
# Use cached memory usage
|
||||||
mem_usage=$(echo "$mem_info" | awk -F'\t' '{print $1}' | awk -F'/' '{print $1}')
|
mem_info="${DOCKER_STATS_CACHE[$cid]:-}"
|
||||||
mem_perc=$(echo "$mem_info" | awk -F'\t' '{print $2}')
|
if [ -z "$mem_info" ]; then
|
||||||
|
# Fallback: get stats for this specific container if not in cache
|
||||||
|
mem_info=$(docker stats --no-stream --format "{{.MemUsage}}\t{{.MemPerc}}" "$cid" 2>/dev/null || echo "")
|
||||||
|
[ -z "$mem_info" ] && continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
mem_usage=$(echo "$mem_info" | awk -F'\t' '{print $1}' | awk -F'/' '{print $1}' | xargs)
|
||||||
|
mem_perc=$(echo "$mem_info" | awk -F'\t' '{print $2}' | xargs)
|
||||||
|
|
||||||
|
# If we don't have percentage, try to get it separately
|
||||||
|
if [ -z "$mem_perc" ]; then
|
||||||
|
mem_perc=$(docker stats --no-stream --format "{{.MemPerc}}" "$cid" 2>/dev/null || echo "")
|
||||||
|
fi
|
||||||
|
|
||||||
printf "%-40s %s\t%s\n" "$service" "$mem_usage" "$mem_perc"
|
printf "%-40s %s\t%s\n" "$service" "$mem_usage" "$mem_perc"
|
||||||
|
|
||||||
mem_mib=$(to_mib "$mem_usage")
|
mem_mib=$(to_mib "$mem_usage")
|
||||||
total_mib=$(echo "$total_mib + $mem_mib" | bc)
|
total_mib=$(echo "$total_mib + $mem_mib" | bc -l | awk '{printf "%.2f", $1}')
|
||||||
done
|
done
|
||||||
|
|
||||||
echo "----------------------------------------"
|
echo "----------------------------------------"
|
||||||
|
|||||||
Reference in New Issue
Block a user