104 lines
2.8 KiB
Bash
104 lines
2.8 KiB
Bash
|
|
#!/usr/bin/env bash
|
||
|
|
set -euo pipefail
|
||
|
|
|
||
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
|
|
JOURNALD_DROP_IN="/etc/systemd/journald.conf.d/ailab-limits.conf"
|
||
|
|
DOCKER_CONFIG="/etc/docker/daemon.json"
|
||
|
|
packages=(
|
||
|
|
logrotate
|
||
|
|
needrestart
|
||
|
|
smartmontools
|
||
|
|
nvme-cli
|
||
|
|
sysstat
|
||
|
|
iotop
|
||
|
|
ncdu
|
||
|
|
duf
|
||
|
|
jq
|
||
|
|
lsof
|
||
|
|
psmisc
|
||
|
|
tar
|
||
|
|
gzip
|
||
|
|
)
|
||
|
|
timers=(
|
||
|
|
ailab-apt-cleanup.timer
|
||
|
|
ailab-kernel-cleanup.timer
|
||
|
|
ailab-docker-cleanup.timer
|
||
|
|
ailab-config-backup.timer
|
||
|
|
ailab-disk-watch.timer
|
||
|
|
)
|
||
|
|
|
||
|
|
if ((EUID != 0)); then
|
||
|
|
printf 'CRITICAL: install.sh must run as root\n' >&2
|
||
|
|
exit 2
|
||
|
|
fi
|
||
|
|
for command_name in apt-get install systemctl; do
|
||
|
|
if ! command -v "$command_name" >/dev/null 2>&1; then
|
||
|
|
printf 'CRITICAL: required command is missing: %s\n' "$command_name" >&2
|
||
|
|
exit 2
|
||
|
|
fi
|
||
|
|
done
|
||
|
|
|
||
|
|
printf 'Installing maintenance dependencies...\n'
|
||
|
|
apt-get update
|
||
|
|
DEBIAN_FRONTEND=noninteractive apt-get install -y "${packages[@]}"
|
||
|
|
|
||
|
|
printf 'Installing scripts and systemd units...\n'
|
||
|
|
for script in "$SCRIPT_DIR"/scripts/*.sh; do
|
||
|
|
install -m 0755 "$script" "/usr/local/sbin/$(basename "$script")"
|
||
|
|
done
|
||
|
|
for unit in "$SCRIPT_DIR"/systemd/*.{service,timer}; do
|
||
|
|
install -m 0644 "$unit" "/etc/systemd/system/$(basename "$unit")"
|
||
|
|
done
|
||
|
|
|
||
|
|
install -d -m 0755 "$(dirname "$JOURNALD_DROP_IN")"
|
||
|
|
tmp_journald="$(mktemp)"
|
||
|
|
trap 'rm -f "$tmp_journald" "${tmp_docker:-}"' EXIT
|
||
|
|
cat >"$tmp_journald" <<'EOF'
|
||
|
|
[Journal]
|
||
|
|
SystemMaxUse=1G
|
||
|
|
SystemKeepFree=2G
|
||
|
|
MaxRetentionSec=14day
|
||
|
|
Compress=yes
|
||
|
|
EOF
|
||
|
|
install -m 0644 "$tmp_journald" "$JOURNALD_DROP_IN"
|
||
|
|
systemctl restart systemd-journald
|
||
|
|
|
||
|
|
if command -v docker >/dev/null 2>&1; then
|
||
|
|
printf 'Configuring Docker log rotation limits...\n'
|
||
|
|
install -d -m 0755 /etc/docker
|
||
|
|
tmp_docker="$(mktemp)"
|
||
|
|
|
||
|
|
if [[ -f "$DOCKER_CONFIG" ]]; then
|
||
|
|
if ! jq empty "$DOCKER_CONFIG" >/dev/null 2>&1; then
|
||
|
|
printf 'CRITICAL: %s is not valid JSON; refusing to overwrite it\n' "$DOCKER_CONFIG" >&2
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
backup="$DOCKER_CONFIG.$(date '+%Y%m%d-%H%M%S').bak"
|
||
|
|
install -m 0644 "$DOCKER_CONFIG" "$backup"
|
||
|
|
jq '. + {
|
||
|
|
"log-driver": "json-file",
|
||
|
|
"log-opts": ((."log-opts" // {}) + {"max-size": "50m", "max-file": "5"})
|
||
|
|
}' "$DOCKER_CONFIG" >"$tmp_docker"
|
||
|
|
else
|
||
|
|
jq -n '{
|
||
|
|
"log-driver": "json-file",
|
||
|
|
"log-opts": {"max-size": "50m", "max-file": "5"}
|
||
|
|
}' >"$tmp_docker"
|
||
|
|
fi
|
||
|
|
|
||
|
|
jq empty "$tmp_docker"
|
||
|
|
install -m 0644 "$tmp_docker" "$DOCKER_CONFIG"
|
||
|
|
systemctl restart docker || true
|
||
|
|
else
|
||
|
|
printf 'INFO: Docker is not installed; Docker daemon configuration was skipped\n'
|
||
|
|
fi
|
||
|
|
|
||
|
|
systemctl daemon-reload
|
||
|
|
systemctl enable --now "${timers[@]}"
|
||
|
|
|
||
|
|
printf '\nEnabled AI Lab timers:\n'
|
||
|
|
systemctl list-timers --all --no-pager | grep 'ailab-' || true
|
||
|
|
|
||
|
|
/usr/local/sbin/ailab-healthcheck.sh > /root/ailab-healthcheck-now.txt
|
||
|
|
printf '\nOK: installation complete; initial health report: /root/ailab-healthcheck-now.txt\n'
|