232 lines
6.8 KiB
Bash
Executable File
232 lines
6.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# -------------------------------
|
|
# Configurable knobs (env overrides)
|
|
# -------------------------------
|
|
MIRAGE_USER="${MIRAGE_USER:-mirage}"
|
|
MIRAGE_GROUP="${MIRAGE_GROUP:-mirage}"
|
|
|
|
MIRROR_ROOT="${MIRAGE_MIRROR_ROOT:-/srv/www/mirrors}"
|
|
DATA_DIR="${MIRAGE_DATA_DIR:-/var/lib/mirage}"
|
|
LOG_DIR="${MIRAGE_LOG_DIR:-/var/log/mirage}"
|
|
VENV_DIR="${MIRAGE_VENV_DIR:-/opt/mirage/venv}"
|
|
|
|
PYTHON_BIN="${PYTHON_BIN:-python3}"
|
|
|
|
MIRAGE_BIN_LINK="${MIRAGE_BIN_LINK:-/usr/local/bin/mirage}"
|
|
CONFIG_DIR="/etc/mirage"
|
|
CONFIG_FILE="$CONFIG_DIR/config.toml"
|
|
|
|
# -------------------------------
|
|
# Sanity checks
|
|
# -------------------------------
|
|
if [ "$(id -u)" -ne 0 ]; then
|
|
echo "ERROR: install.sh must be run as root (e.g. via sudo)" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if ! command -v "$PYTHON_BIN" >/dev/null 2>&1; then
|
|
echo "ERROR: $PYTHON_BIN not found" >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "==> Using python: $PYTHON_BIN"
|
|
echo "==> Mirage user: $MIRAGE_USER"
|
|
echo "==> Mirage group: $MIRAGE_GROUP"
|
|
echo "==> Mirror root: $MIRROR_ROOT"
|
|
echo "==> Data dir: $DATA_DIR"
|
|
echo "==> Log dir: $LOG_DIR"
|
|
echo "==> Venv dir: $VENV_DIR"
|
|
echo "==> Config file: $CONFIG_FILE"
|
|
echo "==> CLI symlink: $MIRAGE_BIN_LINK"
|
|
echo
|
|
|
|
# -------------------------------
|
|
# Create group/user
|
|
# -------------------------------
|
|
echo "==> Creating mirage user/group (if needed)"
|
|
if ! getent group "$MIRAGE_GROUP" >/dev/null 2>&1; then
|
|
groupadd --system "$MIRAGE_GROUP"
|
|
fi
|
|
|
|
if ! id "$MIRAGE_USER" >/dev/null 2>&1; then
|
|
useradd --system --no-create-home \
|
|
--gid "$MIRAGE_GROUP" \
|
|
--home-dir "$DATA_DIR" \
|
|
--shell /usr/bin/nologin \
|
|
"$MIRAGE_USER"
|
|
fi
|
|
|
|
# -------------------------------
|
|
# Directories & permissions
|
|
# -------------------------------
|
|
echo "==> Creating data/log/mirror directories"
|
|
mkdir -p "$MIRROR_ROOT" "$DATA_DIR" "$LOG_DIR"
|
|
|
|
# Own everything by mirage:mirage
|
|
chown -R "$MIRAGE_USER:$MIRAGE_GROUP" "$MIRROR_ROOT" "$DATA_DIR" "$LOG_DIR"
|
|
|
|
# Ensure perms and setgid bits every run:
|
|
# - owner/group: rwx
|
|
# - others: no access
|
|
# - setgid: new files inherit group 'mirage'
|
|
chmod 2770 "$MIRROR_ROOT" "$DATA_DIR" "$LOG_DIR"
|
|
chmod -R u+rwX,g+rwX,o-rwx "$MIRROR_ROOT" "$DATA_DIR" "$LOG_DIR"
|
|
|
|
# -------------------------------
|
|
# Config file
|
|
# -------------------------------
|
|
echo "==> Installing default config in /etc/mirage (if missing)"
|
|
mkdir -p "$CONFIG_DIR"
|
|
|
|
if [ -f "$CONFIG_FILE" ]; then
|
|
echo " Config already exists at $CONFIG_FILE (leaving it untouched)"
|
|
else
|
|
if [ -f "./etc/mirage/config.toml" ]; then
|
|
echo " Using repo template ./etc/mirage/config.toml"
|
|
install -D -m 644 ./etc/mirage/config.toml "$CONFIG_FILE"
|
|
else
|
|
echo " No template found, generating a basic config at $CONFIG_FILE"
|
|
cat >"$CONFIG_FILE" <<EOF
|
|
# Mirage configuration
|
|
# This file was generated by scripts/install.sh
|
|
# Paths must be writable by the 'mirage' user/group.
|
|
|
|
# Root directory where mirror content is stored.
|
|
mirror_root = "${MIRROR_ROOT}"
|
|
|
|
# Directory for Mirage internal state (queue DB, jobs, etc.)
|
|
data_dir = "${DATA_DIR}"
|
|
|
|
# Directory for log files (per-mirror logs, daemon logs, etc.)
|
|
log_dir = "${LOG_DIR}"
|
|
|
|
# Path to wget binary
|
|
wget_bin = "/usr/bin/wget"
|
|
|
|
# Path to ripgrep (rg) binary
|
|
rg_bin = "/usr/bin/rg"
|
|
|
|
# Maximum number of concurrent mirror updates
|
|
max_concurrent_updates = 4
|
|
EOF
|
|
chmod 644 "$CONFIG_FILE"
|
|
fi
|
|
fi
|
|
|
|
# Typical /etc ownership: root:root
|
|
chown root:root "$CONFIG_FILE"
|
|
|
|
# -------------------------------
|
|
# Virtualenv + Python package
|
|
# -------------------------------
|
|
if [ -d "$VENV_DIR" ]; then
|
|
echo "==> Reusing existing virtualenv at $VENV_DIR"
|
|
else
|
|
echo "==> Creating virtualenv at $VENV_DIR"
|
|
mkdir -p "$(dirname "$VENV_DIR")"
|
|
"$PYTHON_BIN" -m venv "$VENV_DIR"
|
|
fi
|
|
|
|
echo "==> Installing mirage into virtualenv"
|
|
"$VENV_DIR/bin/pip" install --upgrade pip setuptools wheel
|
|
"$VENV_DIR/bin/pip" install .
|
|
|
|
MIRAGE_BIN="$VENV_DIR/bin/mirage"
|
|
|
|
if [ ! -x "$MIRAGE_BIN" ]; then
|
|
echo "ERROR: $MIRAGE_BIN not found or not executable" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# -------------------------------
|
|
# CLI symlink
|
|
# -------------------------------
|
|
echo "==> Installing mirage CLI symlink at $MIRAGE_BIN_LINK"
|
|
if [ -L "$MIRAGE_BIN_LINK" ] || [ -e "$MIRAGE_BIN_LINK" ]; then
|
|
if [ -L "$MIRAGE_BIN_LINK" ] && [ "$(readlink -f "$MIRAGE_BIN_LINK")" = "$MIRAGE_BIN" ]; then
|
|
echo " Symlink already points to $MIRAGE_BIN (leaving it)"
|
|
else
|
|
echo " WARNING: $MIRAGE_BIN_LINK already exists and is not a symlink to $MIRAGE_BIN"
|
|
echo " Not overwriting it. Adjust or remove manually if you want mirage there."
|
|
fi
|
|
else
|
|
ln -s "$MIRAGE_BIN" "$MIRAGE_BIN_LINK"
|
|
echo " Created symlink: $MIRAGE_BIN_LINK -> $MIRAGE_BIN"
|
|
fi
|
|
|
|
# -------------------------------
|
|
# systemd units
|
|
# -------------------------------
|
|
if command -v systemctl >/dev/null 2>&1; then
|
|
echo "==> Installing systemd units"
|
|
install -D -m 644 systemd/mirage.service /etc/systemd/system/mirage.service
|
|
install -D -m 644 systemd/mirage-api.service /etc/systemd/system/mirage-api.service
|
|
install -D -m 644 systemd/mirage-update.service /etc/systemd/system/mirage-update.service
|
|
install -D -m 644 systemd/mirage-update.timer /etc/systemd/system/mirage-update.timer
|
|
|
|
echo "==> Reloading systemd"
|
|
systemctl daemon-reload
|
|
|
|
echo "==> Enabling and starting mirage daemon + api + timer"
|
|
systemctl enable --now mirage.service
|
|
systemctl enable --now mirage-api.service
|
|
systemctl enable --now mirage-update.timer
|
|
else
|
|
echo "==> systemctl not found; skipping systemd unit installation."
|
|
fi
|
|
|
|
# -------------------------------
|
|
# Add installing user to group (docker-style)
|
|
# -------------------------------
|
|
ADDED_USER=""
|
|
INSTALL_USER="${SUDO_USER:-}"
|
|
|
|
if [ -n "$INSTALL_USER" ] && [ "$INSTALL_USER" != "root" ]; then
|
|
if id "$INSTALL_USER" >/dev/null 2>&1; then
|
|
if id -nG "$INSTALL_USER" | tr ' ' '\n' | grep -qx "$MIRAGE_GROUP"; then
|
|
echo "==> User $INSTALL_USER is already in group $MIRAGE_GROUP"
|
|
else
|
|
echo "==> Adding $INSTALL_USER to group $MIRAGE_GROUP"
|
|
usermod -aG "$MIRAGE_GROUP" "$INSTALL_USER"
|
|
ADDED_USER="$INSTALL_USER"
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
# -------------------------------
|
|
# Summary
|
|
# -------------------------------
|
|
cat <<EOF
|
|
|
|
==> Install complete.
|
|
|
|
Mirrors root : $MIRROR_ROOT
|
|
Data dir : $DATA_DIR
|
|
Log dir : $LOG_DIR
|
|
Config : $CONFIG_FILE
|
|
Venv : $VENV_DIR
|
|
Binary : $MIRAGE_BIN
|
|
Symlink : $MIRAGE_BIN_LINK
|
|
EOF
|
|
|
|
if [ -n "$ADDED_USER" ]; then
|
|
cat <<EOF
|
|
|
|
User '$ADDED_USER' was added to the '$MIRAGE_GROUP' group.
|
|
|
|
To use 'mirage' without sudo *immediately* in your current shell, run:
|
|
|
|
newgrp $MIRAGE_GROUP
|
|
|
|
Otherwise, log out and back in so your group membership is refreshed.
|
|
EOF
|
|
else
|
|
echo
|
|
echo "If you want a non-root user to manage mirrors, add them to the '$MIRAGE_GROUP' group:"
|
|
echo
|
|
echo " sudo usermod -aG $MIRAGE_GROUP <username>"
|
|
echo
|
|
fi
|