feat: Check available memory before installation starts (#1353)

This commit is contained in:
Kroese
2026-08-07 02:52:21 +02:00
committed by GitHub
parent 615fad2a0d
commit 438e992653
10 changed files with 181 additions and 93 deletions
+5 -13
View File
@@ -29,10 +29,6 @@ RUN <<EOF
procps \
ipcalc \
ethtool \
python3 \
python3-pip \
python3-msgpack \
python3-pysodium \
xz-utils \
iptables \
iproute2 \
@@ -48,7 +44,11 @@ RUN <<EOF
inotify-tools \
ca-certificates \
netcat-openbsd \
qemu-system-x86
qemu-system-x86 \
python3 \
python3-pip \
python3-msgpack \
python3-pysodium
# Install Passt package
wget "https://github.com/qemus/passt/releases/download/v${VERSION_PASST}/passt_${VERSION_PASST}_${TARGETARCH}.deb" -O /tmp/passt.deb -q --timeout=10
@@ -59,14 +59,6 @@ RUN <<EOF
# Install Python dependencies
pip3 install --no-cache-dir --break-system-packages --root-user-action=ignore "dissect.cstruct==$VERSION_CSTRUCT"
# Configure QEMU
mkdir -p /etc/qemu
echo "allow br0" > /etc/qemu/bridge.conf
# Configure nginx
unlink /etc/nginx/sites-enabled/default
sed -i 's/^worker_processes.*/worker_processes 1;/' /etc/nginx/nginx.conf
# Set version file
echo "$VERSION_ARG" > /etc/version
+2
View File
@@ -61,6 +61,8 @@ buildArguments() {
return 0
}
finalizeMemory
configureMemory
configureMonitor
configureMachine
+2 -2
View File
@@ -9,7 +9,8 @@ cd /run
. start.sh # Startup hook
. utils.sh # Load functions
. reset.sh # Initialize system
. init.sh # Initialize system
. memory.sh # Check memory
. server.sh # Start webserver
. install.sh # Run installation
. disk.sh # Initialize disks
@@ -18,7 +19,6 @@ cd /run
. proc.sh # Initialize processor
. serial.sh # Initialize serialport
. power.sh # Configure shutdown
. memory.sh # Check available memory
. config.sh # Configure arguments
. finish.sh # Finish initialization
+3
View File
@@ -5,4 +5,7 @@ if enabled "$DEBUG"; then
printf "QEMU arguments:\n\n %s\n\n" "${ARGS// -/$'\n -'}"
fi
# Must always remain the very last command
enableTrap
return 0
+1 -48
View File
@@ -158,53 +158,6 @@ checkHost() {
return 0
}
checkRam() {
# Read host and container memory limits.
getMemoryInfo
RAM_SPARE=500000000
RAM_MINIMUM="${RAM_MINIMUM:-1073741824}"
RAM_MINIMUM=$(strip "$RAM_MINIMUM")
RAM_MINIMUM="${RAM_MINIMUM// /}"
RAM_MINIMUM=$(echo "${RAM_MINIMUM^^}" | sed 's/MB/M/g;s/GB/G/g;s/TB/T/g')
numfmt --from=iec "$RAM_MINIMUM" &>/dev/null || {
error "Invalid RAM_MINIMUM: $RAM_MINIMUM"
exit 16
}
RAM_MINIMUM=$(numfmt --from=iec "$RAM_MINIMUM")
RAM_SIZE=$(strip "$RAM_SIZE")
RAM_SIZE="${RAM_SIZE// /}"
[ -z "$RAM_SIZE" ] && RAM_SIZE="2G"
if [[ "${RAM_SIZE,,}" != "max" && "${RAM_SIZE,,}" != "half" ]]; then
# Bare values below 130 are interpreted as GiB for convenience; larger bare
# values are treated as MiB to preserve historical configurations.
if [ -z "${RAM_SIZE//[0-9. ]}" ]; then
[ "${RAM_SIZE%%.*}" -lt "130" ] && RAM_SIZE="${RAM_SIZE}G" || RAM_SIZE="${RAM_SIZE}M"
fi
RAM_SIZE=$(echo "${RAM_SIZE^^}" | sed 's/MB/M/g;s/GB/G/g;s/TB/T/g')
numfmt --from=iec "$RAM_SIZE" &>/dev/null || {
error "Invalid RAM_SIZE: $RAM_SIZE"
exit 16
}
wanted=$(numfmt --from=iec "$RAM_SIZE")
if [ "$wanted" -lt "$RAM_MINIMUM" ]; then
error "$(app) requires at least $(formatBytes "$RAM_MINIMUM") of RAM, but RAM_SIZE is set to $(formatBytes "$wanted")."
exit 16
fi
fi
return 0
}
checkKvm() {
# Check KVM support
@@ -311,7 +264,7 @@ IFS=. read -r KERNEL MINOR _ <<< "$SYS"
checkSockets
checkCores
checkStorage
checkRam
getMemoryInfo
# Print system info
SYS="${SYS/-generic/}"
+116 -14
View File
@@ -1,14 +1,61 @@
#!/usr/bin/env bash
set -Eeuo pipefail
msg="Checking memory..."
enabled "$DEBUG" && echo "$msg"
normalizeMemory() {
RAM_WARNING=""
RAM_ALLOCATION=""
local wanted
RAM_SPARE=500000000
RAM_MINIMUM="${RAM_MINIMUM:-1073741824}"
RAM_MINIMUM=$(strip "$RAM_MINIMUM")
RAM_MINIMUM="${RAM_MINIMUM// /}"
RAM_MINIMUM=$(echo "${RAM_MINIMUM^^}" | sed 's/MB/M/g;s/GB/G/g;s/TB/T/g')
numfmt --from=iec "$RAM_MINIMUM" &>/dev/null || {
error "Invalid RAM_MINIMUM: $RAM_MINIMUM"
exit 16
}
RAM_MINIMUM=$(numfmt --from=iec "$RAM_MINIMUM")
RAM_SIZE=$(strip "$RAM_SIZE")
RAM_SIZE="${RAM_SIZE// /}"
[ -z "$RAM_SIZE" ] && RAM_SIZE="2G"
if [[ "${RAM_SIZE,,}" != "max" && "${RAM_SIZE,,}" != "half" ]]; then
# Bare values below 130 are interpreted as GiB for convenience; larger bare
# values are treated as MiB to preserve historical configurations.
if [ -z "${RAM_SIZE//[0-9. ]}" ]; then
[ "${RAM_SIZE%%.*}" -lt "130" ] && RAM_SIZE="${RAM_SIZE}G" || RAM_SIZE="${RAM_SIZE}M"
fi
RAM_SIZE=$(echo "${RAM_SIZE^^}" | sed 's/MB/M/g;s/GB/G/g;s/TB/T/g')
numfmt --from=iec "$RAM_SIZE" &>/dev/null || {
error "Invalid RAM_SIZE: $RAM_SIZE"
exit 16
}
wanted=$(numfmt --from=iec "$RAM_SIZE")
if [ "$wanted" -lt "$RAM_MINIMUM" ]; then
error "$(app) requires at least $(formatBytes "$RAM_MINIMUM") of RAM, but RAM_SIZE is set to $(formatBytes "$wanted")."
exit 16
fi
# QEMU requires a whole-number memory value, so convert decimal sizes to MiB.
if [[ "$RAM_SIZE" == *.* ]]; then
RAM_SIZE="$(( wanted / 1048576 ))M"
fi
fi
return 0
}
checkConfiguredMemory() {
local final="$1"
if disabled "$RAM_CHECK" || [[ "${RAM_SIZE,,}" == "max" || "${RAM_SIZE,,}" == "half" ]]; then
return 0
fi
@@ -25,7 +72,7 @@ checkConfiguredMemory() {
# heuristic remains informational instead of rewriting RAM_SIZE.
if [[ "${FS,,}" == "zfs" ]]; then
info "$msg but since ZFS is active this will be ignored."
enabled "$final" && info "$msg but since ZFS is active this will be ignored."
else
@@ -41,9 +88,9 @@ checkConfiguredMemory() {
local msg="your configured RAM_SIZE of ${RAM_SIZE/G/ GB} is very close to the $avail_mem of free memory available,"
if [[ "${FS,,}" == "zfs" ]]; then
info "$msg but since ZFS is active this will be ignored."
enabled "$final" && info "$msg but since ZFS is active this will be ignored."
else
warn "$msg please consider a lower amount."
enabled "$final" && warn "$msg please consider a lower amount."
fi
fi
@@ -107,27 +154,82 @@ configureMaxMemory() {
return 0
}
showMemoryLimitHint() {
local kernel
kernel=$(uname -r)
if [[ "${kernel,,}" == *-wsl2* ]]; then
echo
info "Docker Desktop (WSL2) is detected, follow these instructions:"
info ""
info "Increase the memory limit in \"%UserProfile%\\.wslconfig\" by setting \"memory=<size>\" under \"[wsl2]\"."
info "Then run \"wsl --shutdown\" in PowerShell and restart Docker Desktop for the new limit to take effect."
echo
fi
return 0
}
checkMinimumMemory() {
local wanted
wanted=$(numfmt --from=iec "$RAM_SIZE")
if [ "$wanted" -lt "$RAM_MINIMUM" ]; then
error "$(app) requires at least $(formatBytes "$RAM_MINIMUM") of RAM, but only $(formatBytes "$wanted") can be allocated."
showMemoryLimitHint
exit 16
fi
return 0
}
getMemoryInfo
checkMemoryAllocation() {
checkConfiguredMemory
configureHalfMemory
configureMaxMemory
checkMinimumMemory
local final="${1:-N}"
local configured
[ -n "$RAM_WARNING" ] && warn "$RAM_WARNING"
[ -n "$RAM_ALLOCATION" ] && info "Allocated $(formatBytes "$RAM_ALLOCATION") of RAM for $(app)."
normalizeMemory
configured="$RAM_SIZE"
RAM_WARNING=""
RAM_ALLOCATION=""
getMemoryInfo
checkConfiguredMemory "$final"
configureHalfMemory
configureMaxMemory
checkMinimumMemory
if enabled "$final"; then
[ -n "$RAM_WARNING" ] && warn "$RAM_WARNING"
[ -n "$RAM_ALLOCATION" ] && info "Allocated $(formatBytes "$RAM_ALLOCATION") of RAM for $(app)."
else
RAM_SIZE="$configured"
fi
return 0
}
checkMemoryRequirement() {
checkMemoryAllocation "N"
return 0
}
finalizeMemory() {
checkMemoryAllocation "Y"
return 0
}
checkMemoryRequirement
return 0
+13
View File
@@ -968,6 +968,17 @@ configurePasst() {
return 0
}
configureBridge() {
local file="/etc/qemu/bridge.conf"
[ -e "$file" ] && return 0
mkdir -p "${file%/*}" || return 0
echo "allow br0" > "$file" || return 0
return 0
}
createBridge() {
local gateway="$1"
@@ -2137,6 +2148,7 @@ showHostInfo() {
echo " DNS: $nameservers"
fi
enabled "$DEBUG" && echo
return 0
}
@@ -2191,6 +2203,7 @@ initializeNetwork() {
configureMTU
configureMAC
configureBridge
showHostInfo
+16 -8
View File
@@ -335,7 +335,7 @@ waitForShutdown() {
return 0
}
graceful_shutdown() {
gracefulShutdown() {
local sig="$1"
local pid code
@@ -387,13 +387,21 @@ graceful_shutdown() {
finish "$code"
}
enabled "$SHUTDOWN" || return 0
enableTrap() {
enabled "$SHUTDOWN" || return 0
# Keep Ctrl-C available to interactive users without installing an unnecessary
# SIGINT handler for background/container execution.
if interactive; then
_trap gracefulShutdown SIGINT
fi
_trap gracefulShutdown SIGTERM SIGHUP SIGABRT SIGQUIT
return 0
}
[ -n "${QEMU_TIMEOUT:-}" ] && TIMEOUT="$QEMU_TIMEOUT"
if interactive; then
_trap graceful_shutdown SIGINT
fi
_trap graceful_shutdown SIGTERM SIGHUP SIGABRT SIGQUIT
return 0
+17 -2
View File
@@ -51,11 +51,26 @@ configureIpv6Listen() {
return 0
}
configureWebServer() {
configureNginx() {
mkdir -p /etc/nginx/sites-enabled || return 1
rm -f /etc/nginx/sites-enabled/default || return 1
if ! sed -i \
-e 's/^worker_processes.*/worker_processes 1;/' \
/etc/nginx/nginx.conf; then
error "Failed to configure nginx!"
return 1
fi
mkdir -p /etc/nginx/sites-enabled
cp /etc/nginx/default.conf /etc/nginx/sites-enabled/web.conf
return 0
}
configureWebServer() {
configureNginx || return 1
configureWebPorts || return 1
configureIpv6Listen || return 1
+6 -6
View File
@@ -7,6 +7,12 @@ info () { printf "%b%s%b" "\E[1;34m \E[1;36m" "${1:-}" "\E[0m\n"; }
error () { printf "%b%s%b" "\E[1;31m " "ERROR: ${1:-}" "\E[0m\n" >&2; }
warn () { printf "%b%s%b" "\E[1;31m " "Warning: ${1:-}" "\E[0m\n" >&2; }
app() {
echo "Virtual DSM"
return 0
}
readPidFile() {
local -n _pid="$1"
@@ -307,12 +313,6 @@ makeDir() {
return 0
}
app() {
echo "Virtual DSM"
return 0
}
finiteMemoryLimit() {
local limit="$1"