Last active
February 7, 2024 16:01
-
-
Save stylefish/d337d787e9a643d3a8cd6b520aae0259 to your computer and use it in GitHub Desktop.
automatic memory for kvm balooning guests using virsh
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# can be intsalled as a systemd service via | |
# sudo systemctl edit --full --force virshautomem | |
# | |
# [Unit] | |
# Description=virsh auto memory allocation for ballooning vms | |
# | |
# [Service] | |
# ExecStart=/usr/local/bin/virshautomem.sh -d | |
# Restart=always | |
# RestartSec=15s | |
# | |
# [Install] | |
# WantedBy=default.target | |
# memory step size in MB to increase/decrease | |
STEP_MB=512 | |
# minimum memory to assign | |
MIN_MEMORY=$((2 * 1024 * 1024)) | |
# lower and upper threshold in percent of complete assigned memory | |
LOWTHRES=12 | |
UPTHRES=17 | |
# Retrieve the connection URI | |
# uri=$(virsh uri) | |
uri="qemu:///system" | |
daemon=0 | |
if [[ "$1" == "-d" ]]; then | |
daemon=1; | |
echo "running as daemon" | |
fi | |
while | |
# Retrieve a list of running VMs | |
running_vms=$(virsh --connect "$uri" list --name --state-running) | |
# echo "checking running vms: $running_vms" | |
# Iterate over each VM | |
for vm_name in $running_vms; do | |
# Retrieve VM XML configuration | |
vm_xml=$(virsh --connect "$uri" dumpxml "$vm_name") | |
# echo "checking $vm_name" | |
# echo "$vm_xml" | |
# Check if the VM has ballooning support | |
if echo "$vm_xml" | grep -q '<memballoon'; then | |
echo -n "adjusting memory for VM: $vm_name: " | |
virsh --connect "$uri" dommemstat --domain "$vm_name" --period 5 > /dev/null | |
# Extract maximum memory from VM info using xmllint and XPath | |
max_memory_value=$(echo "$vm_xml" | xmllint --xpath 'string(/domain/memory)' -) | |
max_memory_unit=$(echo "$vm_xml" | xmllint --xpath 'string(/domain/memory/@unit)' -) | |
# Convert max_memory_value to kilobytes | |
case $max_memory_unit in | |
k | kb | KiB) | |
MAX_MEMORY=$max_memory_value | |
;; | |
m | mb | MiB) | |
MAX_MEMORY=$(($max_memory_value * 1024)) | |
;; | |
g | gb | GiB) | |
MAX_MEMORY=$(($max_memory_value * 1024 * 1024)) | |
;; | |
t | tb) | |
MAX_MEMORY=$(($max_memory_value * 1024 * 1024 * 1024)) | |
;; | |
*) | |
echo "Unsupported memory unit: $max_memory_unit" | |
continue | |
;; | |
esac | |
# Retrieve memory statistics | |
mem_stat=$(virsh --connect "$uri" dommemstat "$vm_name") | |
current_memory=$(echo "$mem_stat" | awk '/actual/ { print $2 }') | |
available_memory=$(echo "$mem_stat" | awk '/usable/ { print $2 }') | |
if [ "$available_memory" = "" ]; then | |
echo "unable to detect available memory, ensure balloning driver installed and set up" | |
continue | |
fi | |
# Calculate memory thresholds | |
lower_threshold=$(($MAX_MEMORY * $LOWTHRES / 100)) | |
upper_threshold=$(($MAX_MEMORY * $UPTHRES / 100)) | |
# Adjust memory allocation | |
if ((available_memory < lower_threshold)); then | |
echo -n "increase " | |
new_memory=$(($current_memory + ($STEP_MB * 1024))) | |
elif ((available_memory > upper_threshold)); then | |
echo -n "decrease " | |
new_memory=$(($current_memory - ($STEP_MB * 1024))) | |
else | |
echo "keeping current $(($current_memory / 1024 ))M avail: $(($available_memory / 1024))M | lowt: $(($lower_threshold / 1024 ))M | upt: $(($upper_threshold / 1024 ))M" | |
continue | |
fi | |
# echo "NEW $new_memory" | |
# Ensure the new memory does not exceed the maximum | |
if (($new_memory > $MAX_MEMORY)); then | |
new_memory=$MAX_MEMORY | |
# echo "assigning MAX $new_memory" | |
fi | |
# Ensure the new memory does not fall below the minimum | |
if (($new_memory < $MIN_MEMORY)); then | |
new_memory=$MIN_MEMORY | |
# echo "assigning MIN $new_memory" | |
fi | |
#echo "c $current_memory, a: $available_memory, lt: $lower_threshold, ut: $upper_threshold, new: $new_memory" | |
echo "max: $(($MAX_MEMORY / 1024 ))M | cur: $(($current_memory / 1024 ))M | avail: $(($available_memory / 1024 ))M | lowt: $(($lower_threshold / 1024 ))M | upt: $(($upper_threshold / 1024 ))M => $(($new_memory / 1024 ))M" | |
# Apply the new memory allocation | |
virsh --connect "$uri" setmem "$vm_name" "$new_memory" | |
fi | |
done | |
# echo "waiting for next execution" | |
[[ "$daemon" == "1" ]] && sleep 7 | |
do true; done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment