You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
DroneDetector/install_all.sh

247 lines
6.9 KiB
Bash

#!/usr/bin/env bash
set -Eeuo pipefail
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
COMPOSE_FILE="${PROJECT_ROOT}/deploy/docker/docker-compose.yml"
SYSTEMD_TARGET_DIR="/etc/systemd/system"
RUN_USER="${SUDO_USER:-${USER}}"
RUN_GROUP="$(id -gn "${RUN_USER}")"
SDR_UNITS=(
dronedetector-sdr-433.service
dronedetector-sdr-750.service
dronedetector-sdr-868.service
dronedetector-sdr-3300.service
dronedetector-sdr-4500.service
dronedetector-sdr-5200.service
dronedetector-sdr-5800.service
dronedetector-sdr-915.service
dronedetector-sdr-1200.service
dronedetector-sdr-2400.service
)
log() {
printf '[install_all] %s\n' "$*"
}
die() {
printf '[install_all] ERROR: %s\n' "$*" >&2
exit 1
}
print_failure_logs() {
log "Collecting diagnostics..."
systemctl --no-pager --full status dronedetector-compose.service || true
for unit in "${SDR_UNITS[@]}"; do
systemctl --no-pager --full status "$unit" || true
done
if command -v docker >/dev/null 2>&1; then
docker compose -f "$COMPOSE_FILE" ps || true
docker compose -f "$COMPOSE_FILE" logs --tail=150 dronedetector-server-to-master || true
docker compose -f "$COMPOSE_FILE" logs --tail=150 dronedetector-nn-server || true
fi
journalctl -u dronedetector-compose.service -n 150 --no-pager || true
for unit in "${SDR_UNITS[@]}"; do
journalctl -u "$unit" -n 120 --no-pager || true
done
}
trap 'rc=$?; if [[ $rc -ne 0 ]]; then print_failure_logs; fi' EXIT
require_root() {
if [[ "${EUID}" -ne 0 ]]; then
log "Switching to root via sudo..."
exec sudo -E bash "$0" "$@"
fi
}
preflight() {
log "Preflight checks"
[[ -f "${PROJECT_ROOT}/.env" ]] || die "Missing ${PROJECT_ROOT}/.env"
[[ -f "${COMPOSE_FILE}" ]] || die "Missing ${COMPOSE_FILE}"
if ! command -v apt-get >/dev/null 2>&1; then
die "This installer currently supports Debian/Ubuntu only (apt-get required)."
fi
local free_mb
free_mb="$(df -Pm "${PROJECT_ROOT}" | awk 'NR==2 {print $4}')"
if [[ -z "$free_mb" || "$free_mb" -lt 10240 ]]; then
die "At least 10 GB free disk space is required."
fi
if ! command -v nvidia-smi >/dev/null 2>&1; then
die "nvidia-smi is required. GPU/NVIDIA driver is not available on host."
fi
log "Preflight OK"
}
install_host_non_python_deps() {
log "Installing host non-python dependencies"
apt-get update
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
ca-certificates \
curl \
gnupg \
lsb-release \
jq \
git \
python3 \
python3-pip \
python3-venv \
build-essential \
pkg-config \
libusb-1.0-0 \
libusb-1.0-0-dev \
hackrf \
gnuradio \
gr-osmosdr
}
setup_sdr_python_env() {
log "Setting up SDR python environment"
local venv_path="${PROJECT_ROOT}/.venv-sdr"
if [[ ! -d "$venv_path" ]]; then
python3 -m venv --system-site-packages "$venv_path"
fi
"$venv_path/bin/pip" install --upgrade pip
"$venv_path/bin/pip" install -r "${PROJECT_ROOT}/deploy/requirements/sdr_host.txt"
chown -R "${RUN_USER}:${RUN_GROUP}" "$venv_path"
}
install_docker_if_needed() {
if command -v docker >/dev/null 2>&1; then
log "Docker already installed"
return
fi
log "Installing Docker Engine"
. /etc/os-release
local distro_id="${ID}"
if [[ "$distro_id" != "ubuntu" && "$distro_id" != "debian" ]]; then
die "Unsupported distro for Docker auto-install: ${distro_id}"
fi
install -m 0755 -d /etc/apt/keyrings
curl -fsSL "https://download.docker.com/linux/${distro_id}/gpg" | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
chmod a+r /etc/apt/keyrings/docker.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/${distro_id} \
${VERSION_CODENAME} stable" | tee /etc/apt/sources.list.d/docker.list >/dev/null
apt-get update
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
systemctl enable --now docker
}
install_nvidia_container_toolkit() {
log "Installing/Configuring NVIDIA Container Toolkit"
if ! dpkg -s nvidia-container-toolkit >/dev/null 2>&1; then
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | \
gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
apt-get update
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends nvidia-container-toolkit
fi
nvidia-ctk runtime configure --runtime=docker
systemctl restart docker
}
build_and_run_compose() {
log "Building and starting Docker services"
docker compose -f "$COMPOSE_FILE" up -d --build
}
install_systemd_units() {
log "Installing systemd units"
install -m 0755 "${PROJECT_ROOT}/deploy/systemd/precheck-sdr.sh" /usr/local/bin/dronedetector-precheck-sdr.sh
local src dst
for src in "${PROJECT_ROOT}"/deploy/systemd/*.service; do
dst="${SYSTEMD_TARGET_DIR}/$(basename "$src")"
sed \
-e "s|__PROJECT_ROOT__|${PROJECT_ROOT}|g" \
-e "s|__RUN_USER__|${RUN_USER}|g" \
-e "s|__RUN_GROUP__|${RUN_GROUP}|g" \
"$src" > "$dst"
done
systemctl daemon-reload
systemctl enable dronedetector-compose.service
systemctl restart dronedetector-compose.service
for unit in "${SDR_UNITS[@]}"; do
systemctl enable "$unit"
systemctl restart "$unit"
done
}
wait_for_systemd_active() {
local unit="$1"
local timeout_seconds="${2:-60}"
local i
for ((i=0; i<timeout_seconds; i++)); do
if systemctl is-active --quiet "$unit"; then
return 0
fi
sleep 1
done
return 1
}
verify_installation() {
log "Verifying services"
wait_for_systemd_active dronedetector-compose.service 30 || die "dronedetector-compose.service is not active"
for unit in "${SDR_UNITS[@]}"; do
wait_for_systemd_active "$unit" 45 || die "$unit is not active"
done
docker compose -f "$COMPOSE_FILE" ps
local running_services
running_services="$(docker compose -f "$COMPOSE_FILE" ps --status running --services || true)"
printf '%s\n' "$running_services" | grep -Fxq "dronedetector-server-to-master" || die "server_to_master is not running"
printf '%s\n' "$running_services" | grep -Fxq "dronedetector-nn-server" || die "NN_server is not running"
log "Verification completed"
}
main() {
require_root "$@"
log "Project root: ${PROJECT_ROOT}"
log "Runtime user: ${RUN_USER}:${RUN_GROUP}"
preflight
install_host_non_python_deps
setup_sdr_python_env
install_docker_if_needed
install_nvidia_container_toolkit
build_and_run_compose
install_systemd_units
verify_installation
log "SUCCESS: DroneDetector installation completed"
}
main "$@"