#!/bin/bash set -e if [[ $EUID -ne 0 ]]; then echo "This script must be run as root (or with sudo)." exit 1 fi echo "Installing required packages..." apt update apt install -y git jq cron # Added 'cron' explicitly just in case echo "Cleaning up any old user crontab entry (prevents duplicates)..." (crontab -l 2>/dev/null | grep -v "/opt/scripts/system-updates/system-updates.sh") | crontab - || true # Ensure cron is running (helps in minimal LXCs) systemctl enable --now cron 2>/dev/null || /etc/init.d/cron start || true echo "Adding job directly to /etc/crontab (most reliable in Proxmox LXC)..." CRON_COMMENT="# System Updates Discord Notification (added $(date '+%Y-%m-%d %H:%M'))" CRON_LINE="0 */6 * * * root /bin/bash /opt/scripts/system-updates/system-updates.sh" # Check if already present (exact match on script path) if grep -qF "/opt/scripts/system-updates/system-updates.sh" /etc/crontab; then echo "Job already exists in /etc/crontab — no changes needed." else # Append safely with blank line separation { echo "" echo "$CRON_COMMENT" echo "$CRON_LINE" } >> /etc/crontab echo "Job added to /etc/crontab." fi # Reload cron to apply changes immediately systemctl restart cron 2>/dev/null || /etc/init.d/cron restart || service cron restart || true # Quick verification (helpful during setup) echo "" echo "Last 10 lines of /etc/crontab (should show your new entry):" tail -n 10 /etc/crontab echo "" echo "Cron service status:" systemctl status cron --no-pager || service cron status || true # ──────────────────────────────────────────────────────────────── echo "Checking for Docker and setting up dockcheck (Docker image update notifier)..." if command -v docker >/dev/null 2>&1; then echo "Docker is installed → proceeding with dockcheck setup." DOCKCHECK_DIR="/opt/dockcheck" # Clone or update dockcheck repo if [ -d "$DOCKCHECK_DIR" ]; then echo "dockcheck already exists, updating..." cd "$DOCKCHECK_DIR" git pull || echo "git pull failed — continuing anyway." cd - >/dev/null else echo "Cloning dockcheck..." git clone https://github.com/mag37/dockcheck.git "$DOCKCHECK_DIR" fi # Ensure we're in the dir cd "$DOCKCHECK_DIR" || { echo "Failed to cd into $DOCKCHECK_DIR — skipping dockcheck."; continue; } # ──────────────────────────────────────────────────────────────── echo "Ensuring regctl dependency is installed (required by dockcheck, non-interactive)..." # Detect architecture (dockcheck supports amd64/arm64 natively; others may need workaround later) ARCH=$(uname -m) case $ARCH in x86_64) REGCTL_ARCH="amd64" ;; aarch64|arm64) REGCTL_ARCH="arm64" ;; *) echo "Warning: Unsupported architecture ($ARCH) for native regctl binary. dockcheck may need a container wrapper later. Skipping auto-install." REGCTL_ARCH="" ;; esac if [ -n "$REGCTL_ARCH" ]; then # Check if regctl already exists in PATH or local dir if ! command -v regctl >/dev/null 2>&1 && [ ! -f "./regctl" ]; then echo "regctl not found → downloading and installing latest static binary (non-interactive)..." # Get latest release tag LATEST_TAG=$(curl -s https://api.github.com/repos/regclient/regclient/releases/latest | grep '"tag_name":' | sed -E 's/.*"tag_name": "v([^"]+)".*/\1/') if [ -z "$LATEST_TAG" ]; then echo "Failed to fetch latest regctl version — skipping install. Manual install may be needed." else # Download binary curl -L -o regctl "https://github.com/regclient/regclient/releases/download/v${LATEST_TAG}/regctl-linux-${REGCTL_ARCH}" || { echo "Download failed — skipping regctl install." continue } chmod +x regctl echo "regctl installed locally in $DOCKCHECK_DIR/regctl" # Optional: Move to /usr/local/bin for global PATH (recommended for cron reliability) # mv regctl /usr/local/bin/regctl || echo "Could not move to /usr/local/bin — keeping local." # But keeping local is fine since dockcheck checks PWD too fi else echo "regctl already present — skipping install." fi else echo "Non-standard arch — regctl not auto-installed. Consider manual setup or wrapper per dockcheck docs." fi # Copy default.config → dockcheck.config (only if missing, to avoid overwriting custom edits) if [ ! -f "dockcheck.config" ]; then if [ -f "default.config" ]; then cp default.config dockcheck.config echo "Created dockcheck.config from default.config" else echo "Warning: default.config not found in repo — skipping config setup." continue fi else echo "dockcheck.config already exists — preserving it and only updating notification settings." fi # Load the existing webhook from system-updates (we already prompted for it earlier) if [ -f "/opt/scripts/system-updates/.webhook" ]; then DISCORD_WEBHOOK=$(> /etc/crontab echo "dockcheck cron job added." fi # Reload cron systemctl restart cron 2>/dev/null || /etc/init.d/cron restart || service cron restart || true # Quick verification echo "" echo "Last 10 lines of /etc/crontab (should show dockcheck entry if added):" tail -n 10 /etc/crontab else echo "Docker not found — skipping dockcheck setup." fi echo "Cloning/updating discord.sh..." mkdir -p /opt cd /opt if [ -d "discord.sh" ]; then echo "discord.sh already exists, updating..." cd discord.sh git pull else git clone https://github.com/fieu/discord.sh.git fi echo "Setting up directory and script..." mkdir -p /opt/scripts/system-updates cd /opt/scripts/system-updates cat > system-updates.sh << 'EOF' #!/bin/bash apt update >/dev/null 2>&1 output=$(apt list --upgradable 2>&1) lth=${#output} if [ "$lth" -gt 10 ]; then apt list --upgradable > /opt/scripts/system-updates/upgrade.list /opt/discord.sh/discord.sh \ --avatar "$(" fi exit 0 EOF chmod +x system-updates.sh # Suppress the apt script warning globally echo 'Apt::Cmd::Disable-Script-Warning "true";' > /etc/apt/apt.conf.d/90disable-script-warning echo "Configuring credentials..." prompt_with_default() { local file="$1" local prompt="$2" local default="" if [[ -f "$file" ]]; then default=$(cat "$file") read -p "$prompt [default: $default]: " input echo "${input:-$default}" else read -p "$prompt: " input echo "$input" fi } NAME=$(prompt_with_default ".username" "Enter the Name (bot username, e.g., container hostname)") echo "$NAME" > .username chmod 600 .username WEBHOOK=$(prompt_with_default ".webhook" "Enter the Discord Webhook URL") echo "$WEBHOOK" > .webhook chmod 600 .webhook if [[ -f ".avatar" ]]; then current_avatar=$(cat .avatar) read -p "Enter Avatar URL [default: $current_avatar]: " AVATAR AVATAR=${AVATAR:-$current_avatar} else read -p "Enter Avatar URL [default: https://extensions.gnome.org/extension-data/icons/icon_1139.png]: " AVATAR AVATAR=${AVATAR:-https://extensions.gnome.org/extension-data/icons/icon_1139.png} fi echo "$AVATAR" > .avatar chmod 600 .avatar echo "" echo "Setup complete! Everything is ready." echo "The apt warning is now suppressed globally." echo "Your default avatar is the system-update packages icon." echo "" read -p "Test it right now and see the notification in Discord? [Y/n] " -n 1 -r echo "" if [[ $REPLY =~ ^[Yy]$ ]] || [[ -z $REPLY ]]; then echo "Running the test now..." echo "Running APT commands (this may take a moment)..." echo "──────────────────────────────" /bin/bash /opt/scripts/system-updates/system-updates.sh echo "──────────────────────────────" echo "Done! Check your Discord channel." else echo "Test skipped. You can always run it later:" echo " /opt/scripts/system-updates/system-updates.sh" fi echo "" echo "All set — clean, quiet, and beautiful notifications await!"