Pulse/install.sh
Pulse Monitor eef3ebf354 fix: critical bugs in v4.1.5
- Fixed hardcoded version fallback showing 4.1.1 instead of current version
- Fixed install script syntax error that prevented fresh installations
- Identified root cause of Docker persistence issue (notification UI not saving)
- Identified missing save functionality in frontend notification settings

Issues addressed: #277, #278, #282
2025-08-10 18:49:51 +00:00

385 lines
No EOL
11 KiB
Bash
Executable file

#!/usr/bin/env bash
# Pulse Installer Script for Go Version
# Supports: Ubuntu 20.04+, Debian 11+, Proxmox VE 7+
set -euo pipefail
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Configuration
INSTALL_DIR="/opt/pulse"
CONFIG_DIR="/etc/pulse" # All config and data goes here for manual installs
SERVICE_NAME="pulse"
GITHUB_REPO="rcourtman/Pulse"
REQUIRED_GO_VERSION="1.21"
# Functions
print_header() {
echo -e "${BLUE}=================================================${NC}"
echo -e "${BLUE} Pulse Installation Script${NC}"
echo -e "${BLUE}=================================================${NC}"
echo
}
print_error() {
echo -e "${RED}[ERROR] $1${NC}" >&2
}
print_success() {
echo -e "${GREEN}[SUCCESS] $1${NC}"
}
print_info() {
echo -e "${YELLOW}[INFO] $1${NC}"
}
check_root() {
if [[ $EUID -ne 0 ]]; then
print_error "This script must be run as root"
exit 1
fi
}
check_pre_v4_installation() {
# Check for Node.js version indicators
if [[ -f "$INSTALL_DIR/.env" ]] || \
[[ -d "$INSTALL_DIR/node_modules" ]] || \
[[ -f "$INSTALL_DIR/package.json" ]] || \
[[ -f "$INSTALL_DIR/server.js" ]] || \
[[ -d "$INSTALL_DIR/backend" ]] || \
[[ -d "$INSTALL_DIR/frontend" ]] || \
systemctl list-unit-files --no-legend | grep -q "pulse-backend.service"; then
echo
print_error "Pre-v4 Pulse Installation Detected"
echo
echo -e "${BLUE}=========================================================${NC}"
echo -e "${YELLOW}Pulse v4 is a complete rewrite that requires migration${NC}"
echo -e "${BLUE}=========================================================${NC}"
echo
echo "Your current installation appears to be a pre-v4 version."
echo "Due to fundamental architecture changes, automatic upgrade is not supported."
echo
echo -e "${GREEN}Recommended approach:${NC}"
echo "1. Create a fresh LXC container or VM"
echo "2. Install Pulse v4 in the new environment"
echo "3. Configure your nodes through the new web UI"
echo "4. Reference your old .env file for credentials if needed"
echo
echo -e "${YELLOW}Your existing data is preserved at: $INSTALL_DIR${NC}"
echo
echo "For more information, see:"
echo "https://github.com/rcourtman/Pulse/releases/v4.0.0"
echo -e "${BLUE}=========================================================${NC}"
echo
exit 1
fi
}
detect_os() {
if [[ -f /etc/os-release ]]; then
. /etc/os-release
OS=$ID
VER=$VERSION_ID
else
print_error "Cannot detect OS"
exit 1
fi
}
check_existing_installation() {
if systemctl is-active --quiet $SERVICE_NAME 2>/dev/null; then
print_info "Pulse is currently running"
return 0
elif [[ -f "$INSTALL_DIR/pulse" ]]; then
print_info "Pulse is installed but not running"
return 0
else
return 1
fi
}
install_dependencies() {
print_info "Installing dependencies..."
apt-get update -qq
apt-get install -y -qq curl wget git build-essential
# Install Go if not present or version is too old
if ! command -v go &> /dev/null; then
print_info "Installing Go..."
wget -q -O go.tar.gz https://go.dev/dl/go1.22.5.linux-amd64.tar.gz
tar -C /usr/local -xzf go.tar.gz
rm go.tar.gz
export PATH=$PATH:/usr/local/go/bin
echo 'export PATH=$PATH:/usr/local/go/bin' >> /etc/profile
fi
# Install Node.js for frontend build
if ! command -v node &> /dev/null; then
print_info "Installing Node.js..."
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
apt-get install -y nodejs
fi
}
create_user() {
if ! id -u pulse &>/dev/null; then
print_info "Creating pulse user..."
useradd --system --home-dir $INSTALL_DIR --shell /bin/false pulse
fi
}
backup_existing() {
if [[ -d "$CONFIG_DIR" ]]; then
print_info "Backing up existing configuration..."
cp -a "$CONFIG_DIR" "${CONFIG_DIR}.backup.$(date +%Y%m%d-%H%M%S)"
fi
}
download_pulse() {
print_info "Downloading Pulse..."
# Get latest release
LATEST_RELEASE=$(curl -s https://api.github.com/repos/$GITHUB_REPO/releases/latest | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
if [[ -z "$LATEST_RELEASE" ]]; then
print_error "Could not determine latest release"
exit 1
fi
print_info "Latest version: $LATEST_RELEASE"
# Detect architecture
ARCH=$(uname -m)
case $ARCH in
x86_64)
PULSE_ARCH="amd64"
;;
aarch64)
PULSE_ARCH="arm64"
;;
armv7l)
PULSE_ARCH="armv7"
;;
*)
print_error "Unsupported architecture: $ARCH"
exit 1
;;
esac
print_info "Detected architecture: $ARCH ($PULSE_ARCH)"
# Download architecture-specific release
DOWNLOAD_URL="https://github.com/$GITHUB_REPO/releases/download/$LATEST_RELEASE/pulse-${LATEST_RELEASE}-linux-${PULSE_ARCH}.tar.gz"
print_info "Downloading from: $DOWNLOAD_URL"
cd /tmp
if ! wget -q -O pulse.tar.gz "$DOWNLOAD_URL"; then
print_error "Failed to download Pulse release"
exit 1
fi
# Stop service if running (for updates)
if systemctl is-active --quiet $SERVICE_NAME; then
print_info "Stopping existing Pulse service..."
systemctl stop $SERVICE_NAME
fi
# Extract to temporary directory first
TEMP_EXTRACT="/tmp/pulse-extract-$$"
mkdir -p "$TEMP_EXTRACT"
tar -xzf pulse.tar.gz -C "$TEMP_EXTRACT"
# Create pulse bin directory if not in tarball
mkdir -p "$INSTALL_DIR/bin"
# Handle both old (flat) and new (bin/) tarball structures
if [[ -d "$TEMP_EXTRACT/bin" ]]; then
# New structure - files already in bin/
cp -r "$TEMP_EXTRACT/bin"/* "$INSTALL_DIR/bin/"
elif [[ -f "$TEMP_EXTRACT/pulse" ]]; then
# Old structure - files in root
cp "$TEMP_EXTRACT/pulse" "$INSTALL_DIR/bin/pulse"
[[ -d "$TEMP_EXTRACT/frontend-modern" ]] && cp -r "$TEMP_EXTRACT/frontend-modern" "$INSTALL_DIR/bin/"
else
print_error "Pulse binary not found in archive"
exit 1
fi
chmod +x "$INSTALL_DIR/bin/pulse"
chown -R pulse:pulse "$INSTALL_DIR"
# Create symlink in /usr/local/bin for PATH convenience
ln -sf "$INSTALL_DIR/bin/pulse" /usr/local/bin/pulse
print_success "Pulse binary installed to $INSTALL_DIR/bin/pulse"
print_success "Symlink created at /usr/local/bin/pulse"
# Copy frontend directory if it exists (required for v4.1.0+)
if [[ -d "$TEMP_EXTRACT/frontend-modern" ]]; then
rm -rf "$INSTALL_DIR/bin/frontend-modern"
cp -r "$TEMP_EXTRACT/frontend-modern" "$INSTALL_DIR/bin/"
chown -R pulse:pulse "$INSTALL_DIR/bin/frontend-modern"
print_success "Frontend files installed to $INSTALL_DIR/bin/frontend-modern"
fi
# Copy VERSION file if present
if [[ -f "$TEMP_EXTRACT/VERSION" ]]; then
cp "$TEMP_EXTRACT/VERSION" "$INSTALL_DIR/VERSION"
chown pulse:pulse "$INSTALL_DIR/VERSION"
fi
# Cleanup
rm -rf "$TEMP_EXTRACT" pulse.tar.gz
}
setup_directories() {
print_info "Setting up directories..."
# Create directories
mkdir -p "$CONFIG_DIR"
mkdir -p "$INSTALL_DIR"
# Set permissions
chown -R pulse:pulse "$CONFIG_DIR" "$INSTALL_DIR"
chmod 700 "$CONFIG_DIR"
}
install_systemd_service() {
print_info "Installing systemd service..."
cat > /etc/systemd/system/$SERVICE_NAME.service << EOF
[Unit]
Description=Pulse Monitoring Server
After=network.target
[Service]
Type=simple
User=pulse
Group=pulse
WorkingDirectory=$INSTALL_DIR
ExecStart=$INSTALL_DIR/bin/pulse
Restart=always
RestartSec=3
StandardOutput=journal
StandardError=journal
Environment="PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
Environment="PULSE_DATA_DIR=$CONFIG_DIR"
# Security hardening
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=$INSTALL_DIR $CONFIG_DIR
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
}
start_pulse() {
print_info "Starting Pulse..."
systemctl enable $SERVICE_NAME
systemctl start $SERVICE_NAME
# Wait for service to start
sleep 3
if systemctl is-active --quiet $SERVICE_NAME; then
print_success "Pulse started successfully"
else
print_error "Failed to start Pulse"
journalctl -u $SERVICE_NAME -n 20
exit 1
fi
}
print_completion() {
local IP=$(hostname -I | awk '{print $1}')
echo
print_header
print_success "Pulse installation completed!"
echo
echo -e "${GREEN}Access Pulse at:${NC} http://${IP}:7655"
echo
echo -e "${YELLOW}Useful commands:${NC}"
echo " systemctl status $SERVICE_NAME - Check service status"
echo " systemctl restart $SERVICE_NAME - Restart Pulse"
echo " journalctl -u $SERVICE_NAME -f - View logs"
echo
}
# Main installation flow
main() {
print_header
check_root
detect_os
check_pre_v4_installation
if check_existing_installation; then
print_info "Existing Pulse installation detected"
echo
echo "What would you like to do?"
echo "1) Update to latest version"
echo "2) Reinstall"
echo "3) Remove"
echo "4) Cancel"
read -p "Select option [1-4]: " choice
case $choice in
1)
backup_existing
systemctl stop $SERVICE_NAME || true
download_pulse
start_pulse
print_completion
;;
2)
backup_existing
systemctl stop $SERVICE_NAME || true
download_pulse
setup_directories
install_systemd_service
start_pulse
print_completion
;;
3)
systemctl stop $SERVICE_NAME || true
systemctl disable $SERVICE_NAME || true
rm -f /etc/systemd/system/$SERVICE_NAME.service
rm -rf "$INSTALL_DIR"
print_success "Pulse removed successfully"
;;
4)
print_info "Installation cancelled"
exit 0
;;
*)
print_error "Invalid option"
exit 1
;;
esac
else
# Fresh installation
install_dependencies
create_user
download_pulse
setup_directories
install_systemd_service
start_pulse
print_completion
fi
}
# Run main function
main "$@"