From 376fac066550f7f24ec1528fbfca40c61d70686d Mon Sep 17 00:00:00 2001 From: Jeremy McClure Date: Sat, 25 Jul 2026 22:42:44 -0400 Subject: [PATCH] netbird-install-update: add install/update script with remote deployment and auto-update timers - Detects Netbird installation method (binary vs package manager) - Replaces package manager installs with binary for consistency - Supports single-host and multi-host SSH deployment - Adds systemd timer for daily auto-updates with persistent scheduling - Handles sudo password automation via --password flag or hosts file - Connection-safe updates using background execution to survive SSH disconnects - Fixes SELinux contexts and binary permissions automatically - Provides detailed deployment summaries with per-host action tracking - Includes SSH timeout handling to prevent hanging on unreachable hosts - Color-coded output with icons for better readability --- README.md | 1 + netbird-install-update/README.md | 444 ++++++++++++++++++ netbird-install-update/hosts.example | 17 + .../netbird-install-update.sh | 434 +++++++++++++++++ netbird-install-update/test-ssh.sh | 16 + 5 files changed, 912 insertions(+) create mode 100644 netbird-install-update/README.md create mode 100644 netbird-install-update/hosts.example create mode 100755 netbird-install-update/netbird-install-update.sh create mode 100644 netbird-install-update/test-ssh.sh diff --git a/README.md b/README.md index f530b5c..dcb4504 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ A collection of utility scripts for Linux desktop and server administration. | [`docker-stacks-backup/`](docker-stacks-backup/) | Backup & restore Docker Compose stacks — named volumes, bind mounts, pre/post hooks, retention, integrity verification | | [`docker-stacks-update/`](docker-stacks-update/) | Discover running Compose stacks, pull latest images, and restart only those that changed | | [`input-remapper-switcher/`](input-remapper-switcher/) | Auto-switch [input-remapper](https://github.com/sezanzeb/input-remapper) presets per-application via Hyprland socket events | +| [`netbird-install-update/`](netbird-install-update/) | Install, update, and manage Netbird across single or multiple Linux hosts — detects install method, replaces package-manager installs with binary, supports SSH remote deployment, auto-update timers, and sudo password automation | | [`proxmox-backup/`](proxmox-backup/) | Backup & restore Proxmox VE configuration (local or over SSH) with integrity verification | | [`proxmox-cloudimg/`](proxmox-cloudimg/) | Download, customize, and create Proxmox VE VM templates from official cloud images | | [`zsh/`](zsh/) | Zsh configuration (`.zshrc`), dependency bootstrap installer, and themed tmux config | diff --git a/netbird-install-update/README.md b/netbird-install-update/README.md new file mode 100644 index 0000000..23b3fec --- /dev/null +++ b/netbird-install-update/README.md @@ -0,0 +1,444 @@ +# Netbird Install/Update Script + +A comprehensive bash script for installing, updating, and managing Netbird across Linux systems. Supports local execution, single-host remote deployment, and multi-host fleet management. + +## Features + +- **Smart Installation**: Automatically detects and handles different Netbird installation methods +- **Package Manager Replacement**: Converts package manager installations to binary installs for better control +- **Connection-Safe Updates**: Background update process survives SSH disconnections during Netbird service restarts +- **Auto-Update Timer**: Systemd timer for daily automatic updates with persistent scheduling +- **Remote Deployment**: Deploy to single hosts or entire fleets via SSH with timeout handling +- **Detailed Summary**: Multi-host deployments show which hosts succeeded/failed and what action was performed +- **SELinux Compatible**: Automatically fixes SELinux contexts on RHEL/Fedora systems +- **No Artifacts**: Clean execution with no leftover files or logs + +## Requirements + +- Linux operating system +- Root/sudo access +- curl +- SSH client (for remote deployment) +- Internet connection to download Netbird + +## Installation + +Make the script executable: + +```bash +chmod +x netbird-install-update.sh +``` + +## Usage + +### Local Execution + +Install or update Netbird on the local machine: + +```bash +./netbird-install-update.sh +``` + +Install with automatic daily updates: + +```bash +./netbird-install-update.sh --timer +``` + +Install with custom update schedule: + +```bash +./netbird-install-update.sh --timer --time "03:00" +``` + +### Single Host Remote Deployment + +Deploy to a remote host via SSH: + +```bash +./netbird-install-update.sh --ssh user@hostname +``` + +Deploy with sudo password (non-interactive): + +```bash +./netbird-install-update.sh --ssh user@hostname --password "your_sudo_password" +``` + +Deploy with auto-update timer enabled: + +```bash +./netbird-install-update.sh --ssh user@hostname --timer +``` + +Deploy with custom update schedule: + +```bash +./netbird-install-update.sh --ssh user@hostname --timer --time "03:00" +``` + +### Multi-Host Fleet Deployment + +Deploy to multiple hosts using a hosts file: + +```bash +./netbird-install-update.sh --file hosts.txt +``` + +Deploy with default sudo password for all hosts: + +```bash +./netbird-install-update.sh --file hosts.txt --password "your_sudo_password" +``` + +Deploy with auto-update timer to all hosts: + +```bash +./netbird-install-update.sh --file hosts.txt --timer +``` + +Deploy with custom update schedule to all hosts: + +```bash +./netbird-install-update.sh --file hosts.txt --timer --time "03:00" +``` + +#### Hosts File Format + +Create a text file with one hostname or IP address per line. Empty lines and comments (starting with `#`) are ignored. + +**Optional: Include sudo password** + +You can optionally include the sudo password after the hostname (separated by space). Host-specific passwords override the default password provided via `--password`. + +```bash +# Production servers (with host-specific sudo passwords) +prod-web-01.example.com MySudoPassword123 +prod-web-02.example.com MySudoPassword456 +prod-db-01.example.com MySudoPassword789 + +# Development servers (will use default password from --password flag) +dev-app-01.example.com +dev-app-02.example.com + +# IP addresses also work +192.168.1.100 +10.0.0.50 MyPassword +``` + +**Password Precedence**: +1. Host-specific password in hosts file (highest priority) +2. Default password from `--password` flag +3. Interactive sudo prompt (if no password provided) + +**Security Warning**: Storing passwords in plain text is not recommended for production environments. Consider using SSH key authentication with passwordless sudo instead. + +**Requirements**: +- If a password is provided (via hosts file or `--password` flag), `sshpass` must be installed on the local machine +- If no password is provided, you'll be prompted to enter the sudo password interactively for each host + +See `hosts.example` for a template. + +## Command-Line Options + +| Option | Description | +|--------|-------------| +| `--ssh ` | Deploy to a single remote host via SSH | +| `--file ` | Deploy to multiple hosts listed in a file | +| `--hosts-file ` | Alias for `--file` | +| `--timer` | Install systemd timer for auto-updates | +| `--time ` | Set update schedule (default: "daily") | +| `--password, -p ` | Default sudo password for remote hosts | + +The `--time` option accepts systemd calendar event format. Examples: +- `daily` - Run once per day at midnight (default) +- `03:00` - Run at 3:00 AM daily +- `Mon,Fri 02:30` - Run at 2:30 AM on Monday and Friday +- `hourly` - Run every hour +- `weekly` - Run once per week + +The `--password` option provides a default sudo password for remote deployments. This can be overridden per-host in the hosts file. + +## How It Works + +### Installation Detection + +The script detects three installation states: + +1. **Not Installed**: Netbird binary not found in PATH +2. **Package Manager Install**: Installed via apt, yum, dnf, zypper, or rpm-ostree +3. **Binary Install**: Installed via the official curl-based installer + +Detection is performed by: +- Checking `/etc/netbird/install.conf` (authoritative source) +- Querying package managers (dpkg, rpm) +- Falling back to binary install detection + +### Installation Flow + +**Fresh Installation (Not Installed)**: +1. Downloads official Netbird install script +2. Runs binary-only installation (no GUI, no package manager) +3. Ensures proper ownership and permissions +4. Fixes SELinux contexts if applicable + +**Package Manager Replacement**: +1. Downloads official Netbird install script +2. Schedules background replacement (3-second delay) +3. Stops Netbird service +4. Removes package manager installation +5. Runs binary installation +6. Ensures proper ownership, permissions, and SELinux contexts + +**Binary Update**: +1. Compares current version with latest release +2. If outdated, schedules background update (3-second delay) +3. Runs official update process +4. Ensures proper ownership, permissions, and SELinux contexts + +### Connection-Safe Updates + +When updating over SSH, the script uses a detached background process to avoid disconnection issues: + +```bash +setsid bash -c 'sleep 3 && [update commands]' /var/log/netbird-update.log 2>&1 & +``` + +The 3-second delay allows the SSH session to complete cleanly before the Netbird service is stopped and restarted. The update continues even if your connection drops. + +### Auto-Update Timer + +When `--timer` is specified, the script creates a systemd timer that: + +- Runs on a configurable schedule (default: daily at midnight with random 0-10 minute delay) +- Uses `Persistent=true` to catch up on missed runs after system boot +- Logs output to `/var/log/netbird-update.log` +- Automatically updates existing timers if already installed + +The schedule can be customized with the `--time` option. Examples: +- `--time "daily"` - Run once per day at midnight (default) +- `--time "03:00"` - Run at 3:00 AM daily +- `--time "Mon,Fri 02:30"` - Run at 2:30 AM on Monday and Friday +- `--time "hourly"` - Run every hour +- `--time "weekly"` - Run once per week + +The timer consists of two systemd units: + +**netbird-update.service**: +```ini +[Service] +Type=oneshot +ExecStart=/bin/bash -c 'curl -fsSL https://pkgs.netbird.io/install.sh | UPDATE_NETBIRD=true sh && chown root:root /usr/bin/netbird 2>/dev/null || true && chmod +x /usr/bin/netbird 2>/dev/null || true && restorecon -v /usr/bin/netbird 2>/dev/null || true' +``` + +**netbird-update.timer**: +```ini +[Timer] +OnCalendar=daily +Persistent=true +RandomizedDelaySec=600 + +[Install] +WantedBy=timers.target +``` + +## Logging + +All background operations log to `/var/log/netbird-update.log`: + +- Package manager replacement operations +- In-place updates +- Systemd timer executions + +Check the log to monitor update progress or troubleshoot issues: + +```bash +sudo tail -f /var/log/netbird-update.log +``` + +## Troubleshooting + +### Netbird Service Fails to Start + +If the Netbird service fails with "Permission denied" errors: + +```bash +# Check binary permissions +ls -la /usr/bin/netbird + +# Fix ownership and permissions +sudo chown root:root /usr/bin/netbird +sudo chmod +x /usr/bin/netbird + +# Fix SELinux context (RHEL/Fedora) +sudo restorecon -v /usr/bin/netbird + +# Restart service +sudo systemctl restart netbird +``` + +### Check Update Status + +```bash +# Check current version +netbird version + +# Check service status +sudo systemctl status netbird + +# View update logs +sudo cat /var/log/netbird-update.log + +# Check timer status (if installed) +systemctl status netbird-update.timer +``` + +### Manual Update + +If you need to manually trigger an update: + +```bash +./netbird-install-update.sh +``` + +Or use the official Netbird update method: + +```bash +curl -fsSL https://pkgs.netbird.io/install.sh | sudo UPDATE_NETBIRD=true sh +``` + +### Timer Management + +```bash +# Check timer status +systemctl status netbird-update.timer + +# View timer schedule +systemctl list-timers netbird-update.timer + +# Manually trigger timer +sudo systemctl start netbird-update.service + +# Disable timer +sudo systemctl disable --now netbird-update.timer + +# Remove timer completely +sudo systemctl disable --now netbird-update.timer +sudo rm /etc/systemd/system/netbird-update.service +sudo rm /etc/systemd/system/netbird-update.timer +sudo systemctl daemon-reload +``` + +## Why Binary Install? + +The script converts package manager installations to binary installs because: + +1. **Better Control**: Direct binary management allows precise version control +2. **Simpler Updates**: Binary updates don't require package manager configuration +3. **Consistency**: Same installation method across all Linux distributions +4. **Official Support**: Binary install is the officially recommended method by Netbird + +## Remote Deployment Details + +When deploying remotely: + +1. Script copies itself to the remote host via `scp` +2. Executes remotely with `sudo` via `ssh -t` (terminal allocation for sudo password prompt) +3. Passes through additional flags (like `--timer`) +4. Cleans up the remote copy after execution + +The remote deployment continues even if the local script is interrupted. + +**Important Requirements**: +- **SSH Authentication**: Remote deployment requires SSH key authentication. Password-based SSH authentication is not supported. +- **Sudo Access**: The script will prompt for the sudo password on each remote host. For fully automated deployments, configure passwordless sudo on the remote hosts (e.g., add a sudoers rule like `username ALL=(ALL) NOPASSWD: /bin/bash`). + +### SSH Timeout and Error Handling + +The script includes a 30-second timeout for SSH connections to prevent hanging on unreachable hosts. If a host is unreachable or the connection times out, the script will: + +- Mark the host as failed in the deployment summary +- Continue to the next host in the list +- Report the failure at the end + +### Deployment Summary + +After multi-host deployment, the script provides a detailed summary showing: + +- **Total successful and failed deployments** +- **List of successful hosts** with the action performed: + - `fresh install` - Netbird was not installed and has been installed + - `pkg replacement` - Netbird was installed via package manager and converted to binary install + - `updated` - Netbird was updated to a newer version + - `up to date` - Netbird was already at the latest version +- **List of failed hosts** that could not be reached or had errors + +Example output: + +``` +╔═══════════════════════════════════════════════════════════════╗ +║ ✓ Deployment Summary +╠═══════════════════════════════════════════════════════════════╣ +║ ✓ Successful: 3 +║ ✗ Failed: 1 +╚═══════════════════════════════════════════════════════════════╝ + +Successful Hosts: + ✓ host-01.example.com (updated) + ✓ host-02.example.com (fresh install) + ✓ host-03.example.com (up to date) + +Failed Hosts: + ✗ host-04.example.com +``` + +## Exit Codes + +- `0`: Success +- `1`: Error (file not found, SSH failure, etc.) + +## Compatibility + +### Tested Package Managers + +- apt (Debian/Ubuntu) +- yum (RHEL/CentOS 7) +- dnf (Fedora/RHEL 8+/CentOS 8+) +- zypper (openSUSE) +- rpm-ostree (Fedora Silverblue) + +### SELinux Support + +Automatically handles SELinux contexts on systems with SELinux enabled (RHEL, Fedora, CentOS). The `restorecon` command is safely ignored on systems without SELinux. + +## Security Considerations + +- Script requires root/sudo access +- Downloads official Netbird installer from `https://pkgs.netbird.io/install.sh` +- All operations are logged to `/var/log/netbird-update.log` +- No credentials are stored or transmitted +- Temporary files are cleaned up automatically + +## Limitations + +- Linux only (no macOS or Windows support) +- Requires SSH key authentication for remote deployment (password authentication is not supported) +- Background updates cannot be cancelled once started + +## License + +This script is provided as-is for managing Netbird installations. Netbird itself is subject to its own license terms. + +## Contributing + +Contributions are welcome! Please ensure: +- Script syntax is valid (`bash -n script.sh`) +- Changes are tested on multiple Linux distributions +- SELinux compatibility is maintained +- No artifacts are left behind after execution + +## Support + +For Netbird-specific issues, refer to the [official Netbird documentation](https://docs.netbird.io). + +For script-specific issues, check the troubleshooting section or review the logs at `/var/log/netbird-update.log`. diff --git a/netbird-install-update/hosts.example b/netbird-install-update/hosts.example new file mode 100644 index 0000000..9f52633 --- /dev/null +++ b/netbird-install-update/hosts.example @@ -0,0 +1,17 @@ +# Example hosts file for netbird-install-update.sh +# Format: hostname [sudo_password] +# One host per line, comments start with # +# Host-specific passwords override --password flag + +# Production servers (with host-specific sudo passwords) +prod-web-01.jeremy.skynet MySudoPassword123 +prod-web-02.jeremy.skynet MySudoPassword123 +prod-db-01.jeremy.skynet MySudoPassword123 + +# Development servers (will use --password flag or prompt interactively) +dev-app-01.jeremy.skynet +dev-app-02.jeremy.skynet + +# You can also use IP addresses +# 192.168.1.100 +# 10.0.0.50 MyPassword diff --git a/netbird-install-update/netbird-install-update.sh b/netbird-install-update/netbird-install-update.sh new file mode 100755 index 0000000..ac6ecaa --- /dev/null +++ b/netbird-install-update/netbird-install-update.sh @@ -0,0 +1,434 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Color codes for output formatting +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +CYAN='\033[0;36m' +BOLD='\033[1m' +DIM='\033[2m' +NC='\033[0m' # No Color + +# Icons +ICON_SUCCESS="✓" +ICON_ERROR="✗" +ICON_INFO="ℹ" +ICON_WARNING="⚠" +ICON_ARROW="→" +ICON_DOWNLOAD="⬇" +ICON_UPLOAD="⬆" +ICON_INSTALL="📦" +ICON_UPDATE="🔄" +ICON_DEPLOY="🚀" +ICON_TIMER="⏰" +ICON_CHECK="🔍" +ICON_CONFIG="⚙" +ICON_NETWORK="🌐" +ICON_VERSION="📋" +ICON_LOG="📝" +ICON_HOST="🖥" + +SSH_HOST="" +HOSTS_FILE="" +INSTALL_TIMER=false +TIMER_TIME="daily" +DEFAULT_PASSWORD="" +REMOTE_ARGS=() +SSH_TIMEOUT=30 + +# Arrays to track deployment results +declare -a SUCCESS_HOSTS=() +declare -a FAILED_HOSTS=() +declare -a HOST_ACTIONS=() + +# Helper functions for formatted output +print_header() { + echo -e "\n${BLUE}${BOLD}╔═══════════════════════════════════════════════════════════════╗${NC}" + echo -e "${BLUE}${BOLD}║ $1${NC}" + echo -e "${BLUE}${BOLD}╚═══════════════════════════════════════════════════════════════╝${NC}\n" +} + +print_info() { + echo -e " ${BLUE}${ICON_INFO}${NC} $1" +} + +print_success() { + echo -e " ${GREEN}${ICON_SUCCESS}${NC} $1" +} + +print_error() { + echo -e " ${RED}${ICON_ERROR}${NC} $1" +} + +print_warning() { + echo -e " ${YELLOW}${ICON_WARNING}${NC} $1" +} + +print_status() { + echo -e " ${CYAN}${ICON_ARROW}${NC} $1" +} + +print_step() { + echo -e " ${DIM}•${NC} $1" +} + +while [[ $# -gt 0 ]]; do + case "$1" in + --ssh) + SSH_HOST="$2" + shift 2 + ;; + --hosts-file|--file) + HOSTS_FILE="$2" + shift 2 + ;; + --timer) + INSTALL_TIMER=true + REMOTE_ARGS+=("--timer") + shift + ;; + --time) + TIMER_TIME="$2" + REMOTE_ARGS+=("--time" "$2") + shift 2 + ;; + --password|-p) + DEFAULT_PASSWORD="$2" + shift 2 + ;; + *) + echo "Unknown option: $1" + exit 1 + ;; + esac +done + +deploy_to_host() { + local host="$1" + local sudo_pass="${2:-}" + echo -e "${CYAN}${BOLD}┌─────────────────────────────────────────────────────────────┐${NC}" + echo -e "${CYAN}${BOLD}│${NC} ${ICON_DEPLOY} ${YELLOW}${host}${NC}" + echo -e "${CYAN}${BOLD}└─────────────────────────────────────────────────────────────┘${NC}" + + REMOTE_SCRIPT="/tmp/.netbird-install-update-$$" + REMOTE_ACTION_FILE="/tmp/.netbird-action-$$" + LOCAL_ACTION_FILE="/tmp/.netbird-deploy-action-$$" + + print_step "Copying script..." + if ! scp -o ConnectTimeout=$SSH_TIMEOUT -o BatchMode=yes "$0" "$host:$REMOTE_SCRIPT" 2>&1; then + print_error "Failed to copy script to $host (timeout or connection error)" + return 1 + fi + + print_step "Executing script..." + # Build SSH command based on whether we have a password + if [ -n "$sudo_pass" ]; then + # Write password to remote temp file using printf to handle special characters + # Use base64 to safely transfer the password + local encoded_pass=$(echo -n "$sudo_pass" | base64) + if ! ssh -o ConnectTimeout=$SSH_TIMEOUT -o StrictHostKeyChecking=no "$host" "echo '$encoded_pass' | base64 -d > /tmp/.netbird-pass-$$ && chmod 600 /tmp/.netbird-pass-$$" 2>&1; then + print_error "Failed to setup password file on $host" + return 1 + fi + + # Execute script with sudo, reading password from file + if ! ssh -o ConnectTimeout=$SSH_TIMEOUT -o StrictHostKeyChecking=no "$host" "sudo -S bash $REMOTE_SCRIPT ${REMOTE_ARGS[*]} < /tmp/.netbird-pass-$$" 2>&1; then + print_error "Failed to execute script on $host" + ssh -o ConnectTimeout=$SSH_TIMEOUT -o StrictHostKeyChecking=no "$host" "rm -f $REMOTE_SCRIPT $REMOTE_ACTION_FILE /tmp/.netbird-pass-$$" 2>/dev/null || true + return 1 + fi + + # Clean up password file + ssh -o ConnectTimeout=$SSH_TIMEOUT -o StrictHostKeyChecking=no "$host" "rm -f /tmp/.netbird-pass-$$" 2>/dev/null || true + else + # Interactive sudo with terminal + if ! ssh -o ConnectTimeout=$SSH_TIMEOUT -o BatchMode=yes -t "$host" "sudo bash $REMOTE_SCRIPT ${REMOTE_ARGS[*]}" 2>&1; then + print_error "Failed to execute script on $host" + ssh -o ConnectTimeout=$SSH_TIMEOUT -o BatchMode=yes "$host" "rm -f $REMOTE_SCRIPT $REMOTE_ACTION_FILE" 2>/dev/null || true + return 1 + fi + fi + + # Read the action from the remote action file and write to local action file + if action_output=$(ssh -o ConnectTimeout=$SSH_TIMEOUT -o StrictHostKeyChecking=no "$host" "cat $REMOTE_ACTION_FILE 2>/dev/null" < /dev/null 2>&1); then + echo "$action_output" > "$LOCAL_ACTION_FILE" + else + echo "unknown" > "$LOCAL_ACTION_FILE" + fi + + # Clean up remote files + ssh -o ConnectTimeout=$SSH_TIMEOUT -o StrictHostKeyChecking=no "$host" "rm -f $REMOTE_SCRIPT $REMOTE_ACTION_FILE" < /dev/null 2>/dev/null || true + print_success "Completed: $host" + return 0 +} + +if [ -n "$HOSTS_FILE" ]; then + if [ ! -f "$HOSTS_FILE" ]; then + print_error "Hosts file not found: $HOSTS_FILE" + exit 1 + fi + + print_header "${ICON_NETWORK} Multi-Host Deployment" + print_info "Reading hosts from: ${YELLOW}$HOSTS_FILE${NC}" + print_info "SSH timeout: ${YELLOW}${SSH_TIMEOUT}s${NC}" + echo "" + + SUCCESS_COUNT=0 + FAIL_COUNT=0 + ACTION_FILE="/tmp/.netbird-deploy-action-$$" + + # Use file descriptor 3 to read hosts file (prevents SSH from consuming stdin) + exec 3< "$HOSTS_FILE" + while IFS= read -r line <&3 || [ -n "$line" ]; do + # Skip empty lines and comments + [[ -z "$line" || "$line" =~ ^[[:space:]]*# ]] && continue + # Trim whitespace + line=$(echo "$line" | xargs) + + # Parse hostname and optional password + host=$(echo "$line" | awk '{print $1}') + sudo_pass=$(echo "$line" | awk '{print $2}') + + # Use default password if no host-specific password is provided + if [ -z "$sudo_pass" ] && [ -n "$DEFAULT_PASSWORD" ]; then + sudo_pass="$DEFAULT_PASSWORD" + fi + + # Run deployment (output streams to terminal) + if deploy_to_host "$host" "$sudo_pass"; then + # Read the action from the temp file + action="unknown" + if [ -f "$ACTION_FILE" ]; then + action=$(cat "$ACTION_FILE") + rm -f "$ACTION_FILE" + fi + SUCCESS_HOSTS+=("$host") + HOST_ACTIONS+=("$action") + ((SUCCESS_COUNT++)) || true + else + FAILED_HOSTS+=("$host") + ((FAIL_COUNT++)) || true + fi + echo "" + done + exec 3<&- + + # Print detailed summary + echo -e "\n${GREEN}${BOLD}╔═══════════════════════════════════════════════════════════════╗${NC}" + echo -e "${GREEN}${BOLD}║${NC} ${ICON_SUCCESS} ${GREEN}${BOLD}Deployment Summary${NC}" + echo -e "${GREEN}${BOLD}╠═══════════════════════════════════════════════════════════════╣${NC}" + echo -e "${GREEN}${BOLD}║${NC} ${GREEN}${ICON_SUCCESS}${NC} Successful: ${BOLD}$SUCCESS_COUNT${NC}" + echo -e "${GREEN}${BOLD}║${NC} ${RED}${ICON_ERROR}${NC} Failed: ${BOLD}$FAIL_COUNT${NC}" + echo -e "${GREEN}${BOLD}╚═══════════════════════════════════════════════════════════════╝${NC}" + + # Show successful hosts with actions + if [ ${#SUCCESS_HOSTS[@]} -gt 0 ]; then + echo -e "\n${GREEN}${BOLD}Successful Hosts:${NC}" + for i in "${!SUCCESS_HOSTS[@]}"; do + host="${SUCCESS_HOSTS[$i]}" + action="${HOST_ACTIONS[$i]}" + echo -e " ${GREEN}${ICON_SUCCESS}${NC} ${YELLOW}$host${NC} ${DIM}($action)${NC}" + done + fi + + # Show failed hosts + if [ ${#FAILED_HOSTS[@]} -gt 0 ]; then + echo -e "\n${RED}${BOLD}Failed Hosts:${NC}" + for host in "${FAILED_HOSTS[@]}"; do + echo -e " ${RED}${ICON_ERROR}${NC} ${YELLOW}$host${NC}" + done + fi + + echo "" + exit 0 +fi + +if [ -n "$SSH_HOST" ]; then + print_header "${ICON_DEPLOY} Single Host Deployment" + ACTION_FILE="/tmp/.netbird-deploy-action-$$" + if deploy_to_host "$SSH_HOST" "$DEFAULT_PASSWORD"; then + # Read and display the action + if [ -f "$ACTION_FILE" ]; then + action=$(cat "$ACTION_FILE") + rm -f "$ACTION_FILE" + print_info "Action performed: ${YELLOW}$action${NC}" + fi + fi + echo "" + exit 0 +fi + +if [ "$EUID" -ne 0 ]; then + print_warning "Elevating to root..." + exec sudo "$0" "$@" +fi + +WORK_DIR=$(mktemp -d) +trap 'rm -rf "$WORK_DIR"' EXIT + +detect_install() { + if ! command -v netbird &>/dev/null; then + echo "none" + return + fi + + if [ -f /etc/netbird/install.conf ]; then + local pm + pm=$(grep -oP 'package_manager=\K.*' /etc/netbird/install.conf 2>/dev/null || true) + if [ "$pm" = "bin" ]; then + echo "bin" + return + elif [ -n "$pm" ]; then + echo "pkg:$pm" + return + fi + fi + + if dpkg -s netbird &>/dev/null; then + echo "pkg:apt" + return + fi + if rpm -q netbird &>/dev/null; then + if command -v dnf &>/dev/null; then + echo "pkg:dnf" + else + echo "pkg:yum" + fi + return + fi + + echo "bin" +} + +install_timer() { + print_header "${ICON_TIMER} Installing Auto-Update Timer" + + if systemctl is-active --quiet netbird-update.timer; then + print_warning "Updating existing timer..." + systemctl stop netbird-update.timer + systemctl disable netbird-update.timer + fi + + cat > /etc/systemd/system/netbird-update.service <<'UNIT' +[Unit] +Description=Netbird Auto-Update + +[Service] +Type=oneshot +ExecStart=/bin/bash -c 'curl -fsSL https://pkgs.netbird.io/install.sh | UPDATE_NETBIRD=true sh && chown root:root /usr/bin/netbird 2>/dev/null || true && chmod +x /usr/bin/netbird 2>/dev/null || true && restorecon -v /usr/bin/netbird 2>/dev/null || true && systemctl restart netbird 2>/dev/null || true' +StandardOutput=append:/var/log/netbird-update.log +StandardError=append:/var/log/netbird-update.log +UNIT + + cat > /etc/systemd/system/netbird-update.timer </dev/null || true + restorecon -v /usr/bin/netbird 2>/dev/null || true + systemctl restart netbird 2>/dev/null || true + print_success "Netbird installed successfully" + echo "fresh install" > /tmp/.netbird-action-$$ + ;; + pkg:*) + print_header "${ICON_UPDATE} Package Manager Replacement" + pm="${state#pkg:}" + print_info "Netbird installed via ${YELLOW}$pm${NC}" + print_info "Replacing with binary install..." + cat > /tmp/.netbird_replace.sh <<'EOF' +#!/usr/bin/env bash +set -euo pipefail +sleep 3 +systemctl stop netbird 2>/dev/null || true +case "$1" in + apt) apt-get remove -y netbird netbird-ui 2>/dev/null || true ;; + yum) yum remove -y netbird netbird-ui 2>/dev/null || true ;; + dnf) dnf remove -y netbird netbird-ui 2>/dev/null || true ;; + zypper) zypper remove -y netbird netbird-ui 2>/dev/null || true ;; + rpm-ostree) rpm-ostree uninstall -y netbird netbird-ui 2>/dev/null || true ;; +esac +USE_BIN_INSTALL=true SKIP_UI_APP=true bash /tmp/.netbird_install.sh +chown root:root /usr/bin/netbird 2>/dev/null || true +chmod +x /usr/bin/netbird 2>/dev/null || true +restorecon -v /usr/bin/netbird 2>/dev/null || true +systemctl restart netbird 2>/dev/null || true +rm -f /tmp/.netbird_replace.sh /tmp/.netbird_install.sh +EOF + chmod +x /tmp/.netbird_replace.sh + cp "$WORK_DIR/install.sh" /tmp/.netbird_install.sh + setsid bash /tmp/.netbird_replace.sh "$pm" /var/log/netbird-update.log 2>&1 & + print_warning "Replacement scheduled in background" + print_info "Connection may drop momentarily" + print_info "Check ${YELLOW}/var/log/netbird-update.log${NC} for progress" + echo "pkg replacement" > /tmp/.netbird-action-$$ + ;; + bin) + print_header "${ICON_VERSION} Binary Update Check" + if [ ! -f /etc/netbird/install.conf ]; then + mkdir -p /etc/netbird + echo "package_manager=bin" > /etc/netbird/install.conf + fi + current=$(netbird version 2>/dev/null || echo "unknown") + latest=$(curl -fsSL https://pkgs.netbird.io/releases/latest 2>/dev/null | grep -oP '"tag_name":\s*"v?\K[^"]+' || echo "unknown") + + print_info "Current version: ${YELLOW}$current${NC}" + print_info "Latest version: ${YELLOW}$latest${NC}" + echo "" + + if [ "$current" = "$latest" ] && [ "$current" != "unknown" ]; then + print_success "Netbird is up to date" + echo "up to date" > /tmp/.netbird-action-$$ + else + print_info "Updating Netbird: ${YELLOW}$current${NC} → ${GREEN}$latest${NC}" + cp "$WORK_DIR/install.sh" /tmp/.netbird_update.sh + setsid bash -c 'sleep 3 && bash /tmp/.netbird_update.sh --update && chown root:root /usr/bin/netbird 2>/dev/null || true && chmod +x /usr/bin/netbird 2>/dev/null || true && restorecon -v /usr/bin/netbird 2>/dev/null || true && systemctl restart netbird 2>/dev/null || true && rm -f /tmp/.netbird_update.sh' \ + /var/log/netbird-update.log 2>&1 & + print_warning "Update scheduled in background" + print_info "Connection may drop momentarily" + print_info "Check ${YELLOW}/var/log/netbird-update.log${NC} for progress" + echo "updated" > /tmp/.netbird-action-$$ + fi + ;; +esac + +if $INSTALL_TIMER; then + install_timer +fi + +echo "" diff --git a/netbird-install-update/test-ssh.sh b/netbird-install-update/test-ssh.sh new file mode 100644 index 0000000..9ecef57 --- /dev/null +++ b/netbird-install-update/test-ssh.sh @@ -0,0 +1,16 @@ +# Test SSH remote execution +echo "=== Testing SSH remote execution ===" +echo "" +echo "Usage examples:" +echo " ./netbird-install-update.sh # Run locally" +echo " ./netbird-install-update.sh --timer # Run locally with auto-update timer" +echo " ./netbird-install-update.sh --ssh user@host # Deploy to remote host" +echo " ./netbird-install-update.sh --ssh user@host --timer # Deploy to remote host with timer" +echo "" +echo "The -ssh flag will:" +echo "1. Copy this script to the remote host via scp" +echo "2. Execute it remotely with sudo" +echo "3. Pass through any other flags (like --timer)" +echo "4. Clean up the remote copy after execution" +echo "" +echo "Script is ready for testing!"