mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-21 18:53:37 +00:00
681c528aff
- Add policykit-1 package to automatic dependency installation - Check for pkexec command availability before installing polkit - Enable sudoless update system to work in LXC environments - Improve compatibility with community Proxmox VE installation scripts This ensures that new installations (including via community scripts) automatically get polkit support for seamless web-based updates without requiring manual sudo commands.
773 lines
23 KiB
Bash
Executable File
773 lines
23 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# Pulse for Proxmox VE - Installer
|
|
# https://github.com/rcourtman/Pulse
|
|
|
|
NODE_MAJOR_VERSION=20
|
|
PULSE_DIR="/opt/pulse"
|
|
OLD_PULSE_DIR="/opt/pulse-proxmox"
|
|
PULSE_USER="pulse"
|
|
SERVICE_NAME="pulse.service"
|
|
REPO_BASE_URL="https://github.com/rcourtman/Pulse"
|
|
SCRIPT_NAME="install-pulse.sh"
|
|
SCRIPT_RAW_URL="https://raw.githubusercontent.com/rcourtman/Pulse/main/scripts/install-pulse.sh"
|
|
CURRENT_SCRIPT_COMMIT_SHA="3721e7709c01526f0dd4f70ef622d874ac71ee49"
|
|
|
|
MODE_UPDATE=""
|
|
INSTALL_MODE=""
|
|
SPECIFIED_VERSION_TAG=""
|
|
TARGET_TAG=""
|
|
INSTALLER_WAS_REEXECUTED=false
|
|
|
|
# Parse command line arguments
|
|
while [[ "$#" -gt 0 ]]; do
|
|
case $1 in
|
|
--update) MODE_UPDATE="true"; shift ;;
|
|
--installer-reexecuted)
|
|
INSTALLER_WAS_REEXECUTED=true
|
|
shift
|
|
;;
|
|
--version)
|
|
if [[ -n "$2" ]] && [[ "$2" != --* ]]; then
|
|
SPECIFIED_VERSION_TAG="$2"
|
|
shift 2
|
|
else
|
|
echo "Error: --version requires a tag name (e.g., v3.16.0)" >&2
|
|
exit 1
|
|
fi
|
|
;;
|
|
*) echo "Unknown parameter: $1"; exit 1 ;;
|
|
esac
|
|
done
|
|
|
|
# Color output functions
|
|
print_info() {
|
|
echo -e "\033[0;36m➜\033[0m $1"
|
|
}
|
|
|
|
print_success() {
|
|
echo -e "\033[0;32m✓\033[0m $1"
|
|
}
|
|
|
|
print_warning() {
|
|
echo -e "\033[0;33m⚠\033[0m $1"
|
|
}
|
|
|
|
print_error() {
|
|
echo -e "\033[0;31m✗\033[0m $1" >&2
|
|
}
|
|
|
|
# Check if running as root
|
|
check_root() {
|
|
if [ "$(id -u)" -ne 0 ]; then
|
|
print_error "This script must be run as root"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Self-update check
|
|
self_update_check() {
|
|
# Skip if running from pipe, in update mode, or already reexecuted
|
|
if [ ! -t 0 ] || [ -n "$MODE_UPDATE" ] || [ "$INSTALLER_WAS_REEXECUTED" = "true" ]; then
|
|
return 0
|
|
fi
|
|
|
|
if ! command -v curl &>/dev/null; then
|
|
print_warning "curl not found, skipping installer update check"
|
|
return 0
|
|
fi
|
|
|
|
# Install jq if needed for robust SHA checking
|
|
if ! command -v jq &>/dev/null; then
|
|
print_info "Installing jq for installer update check..."
|
|
if command -v apt-get &>/dev/null; then
|
|
apt-get update -qq >/dev/null 2>&1
|
|
if apt-get install -y -qq jq >/dev/null 2>&1; then
|
|
print_success "jq installed"
|
|
else
|
|
print_warning "Could not install jq, falling back to simple update check"
|
|
# Fall back to simple diff check
|
|
simple_update_check
|
|
return $?
|
|
fi
|
|
else
|
|
print_warning "Could not install jq, falling back to simple update check"
|
|
simple_update_check
|
|
return $?
|
|
fi
|
|
fi
|
|
|
|
print_info "Checking for installer updates (GitHub API)..."
|
|
|
|
local owner="rcourtman"
|
|
local repo="Pulse"
|
|
local script_path="scripts/install-pulse.sh"
|
|
local branch="main"
|
|
local api_url="https://api.github.com/repos/${owner}/${repo}/commits?path=${script_path}&sha=${branch}&per_page=1"
|
|
|
|
local latest_sha
|
|
latest_sha=$(curl -sL -H "Accept: application/vnd.github.v3+json" "$api_url" | jq -r 'if type=="array" and length > 0 then .[0].sha else empty end')
|
|
|
|
if [ -z "$latest_sha" ] || [ "$latest_sha" = "null" ]; then
|
|
print_warning "Could not check for updates via API"
|
|
return 0
|
|
fi
|
|
|
|
local current_sha="$CURRENT_SCRIPT_COMMIT_SHA"
|
|
if [ -z "$current_sha" ]; then
|
|
print_warning "Current version unknown, skipping update check"
|
|
return 0
|
|
fi
|
|
|
|
if [ "$latest_sha" != "$current_sha" ]; then
|
|
print_warning "New installer version available (${latest_sha:0:7})"
|
|
read -p "Update installer and restart? [Y/n]: " confirm
|
|
|
|
if [[ ! "$confirm" =~ ^[Nn]$ ]]; then
|
|
print_info "Downloading new installer..."
|
|
local temp_script="/tmp/${SCRIPT_NAME}.tmp"
|
|
|
|
if ! curl -sL "$SCRIPT_RAW_URL" -o "$temp_script"; then
|
|
print_error "Failed to download new installer"
|
|
rm -f "$temp_script"
|
|
return 1
|
|
fi
|
|
|
|
# Update the SHA in the downloaded script
|
|
local updated_script="${temp_script}.updated"
|
|
local sha_updated=false
|
|
|
|
while IFS= read -r line || [[ -n "$line" ]]; do
|
|
if [[ "$line" == CURRENT_SCRIPT_COMMIT_SHA=* ]]; then
|
|
echo "CURRENT_SCRIPT_COMMIT_SHA=\"$latest_sha\"" >> "$updated_script"
|
|
sha_updated=true
|
|
else
|
|
echo "$line" >> "$updated_script"
|
|
fi
|
|
done < "$temp_script"
|
|
|
|
if [ "$sha_updated" = false ]; then
|
|
print_error "Failed to update version in new installer"
|
|
rm -f "$temp_script" "$updated_script"
|
|
return 1
|
|
fi
|
|
|
|
# Replace current script
|
|
if ! mv "$updated_script" "$0"; then
|
|
print_error "Failed to update installer"
|
|
rm -f "$temp_script" "$updated_script"
|
|
return 1
|
|
fi
|
|
|
|
chmod +x "$0"
|
|
rm -f "$temp_script"
|
|
|
|
print_success "Installer updated to ${latest_sha:0:7}"
|
|
print_info "Restarting..."
|
|
exec "$0" --installer-reexecuted "$@"
|
|
fi
|
|
else
|
|
print_success "Installer is up to date"
|
|
fi
|
|
}
|
|
|
|
# Simple fallback update check using diff
|
|
simple_update_check() {
|
|
local temp_script="/tmp/install-pulse-new.sh"
|
|
|
|
if curl -sL "$SCRIPT_RAW_URL" -o "$temp_script" 2>/dev/null; then
|
|
if ! diff -q "$0" "$temp_script" >/dev/null 2>&1; then
|
|
print_warning "New installer version might be available"
|
|
read -p "Update installer and restart? [Y/n]: " confirm
|
|
|
|
if [[ ! "$confirm" =~ ^[Nn]$ ]]; then
|
|
cp "$temp_script" "$0"
|
|
chmod +x "$0"
|
|
rm -f "$temp_script"
|
|
print_success "Installer updated"
|
|
exec "$0" "$@"
|
|
fi
|
|
fi
|
|
rm -f "$temp_script"
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
# Print welcome banner
|
|
print_welcome() {
|
|
echo ""
|
|
echo -e "\033[1;34mPulse for Proxmox VE Installer\033[0m"
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo ""
|
|
}
|
|
|
|
# Get latest release tag from GitHub
|
|
get_latest_release_tag() {
|
|
local api_url="https://api.github.com/repos/rcourtman/Pulse/releases/latest"
|
|
local latest_tag
|
|
|
|
latest_tag=$(curl -s "$api_url" | grep '"tag_name"' | sed -E 's/.*"tag_name": "([^"]+)".*/\1/')
|
|
|
|
if [ -z "$latest_tag" ] || [ "$latest_tag" = "null" ]; then
|
|
return 1
|
|
fi
|
|
|
|
echo "$latest_tag"
|
|
}
|
|
|
|
# Check if a release exists
|
|
check_release_exists() {
|
|
local tag=$1
|
|
local api_url="https://api.github.com/repos/rcourtman/Pulse/releases/tags/$tag"
|
|
|
|
curl -s --fail "$api_url" > /dev/null 2>&1
|
|
}
|
|
|
|
# Download and extract tarball
|
|
download_and_extract_tarball() {
|
|
local version=$1
|
|
local temp_dir="/tmp/pulse-install-$$"
|
|
local tarball_url="${REPO_BASE_URL}/releases/download/${version}/pulse-${version}.tar.gz"
|
|
|
|
print_info "Downloading Pulse ${version}..."
|
|
|
|
# Create temporary directory
|
|
mkdir -p "$temp_dir"
|
|
cd "$temp_dir" || exit 1
|
|
|
|
# Download tarball with progress
|
|
if ! curl -L --progress-bar -o "pulse.tar.gz" "$tarball_url"; then
|
|
print_error "Failed to download release"
|
|
rm -rf "$temp_dir"
|
|
return 1
|
|
fi
|
|
|
|
# Extract tarball
|
|
print_info "Extracting files..."
|
|
if ! tar -xzf "pulse.tar.gz"; then
|
|
print_error "Failed to extract files"
|
|
rm -rf "$temp_dir"
|
|
return 1
|
|
fi
|
|
|
|
# Find extracted directory
|
|
local extracted_dir=$(find . -maxdepth 1 -type d -name "pulse-*" | head -1)
|
|
if [ -z "$extracted_dir" ]; then
|
|
print_error "Invalid release archive"
|
|
rm -rf "$temp_dir"
|
|
return 1
|
|
fi
|
|
|
|
# Backup existing data and configuration if updating
|
|
if [ -d "$PULSE_DIR/data" ]; then
|
|
print_info "Backing up user data..."
|
|
cp -r "$PULSE_DIR/data" "$temp_dir/data-backup"
|
|
fi
|
|
|
|
# Backup .env file if it exists
|
|
if [ -f "$PULSE_DIR/.env" ]; then
|
|
print_info "Backing up configuration..."
|
|
cp "$PULSE_DIR/.env" "$temp_dir/.env-backup"
|
|
fi
|
|
|
|
# Remove old installation
|
|
if [ -d "$PULSE_DIR" ]; then
|
|
rm -rf "$PULSE_DIR"
|
|
fi
|
|
|
|
# Move to installation directory
|
|
mv "$extracted_dir" "$PULSE_DIR"
|
|
|
|
# Restore data if it existed
|
|
if [ -d "$temp_dir/data-backup" ]; then
|
|
print_info "Restoring user data..."
|
|
cp -r "$temp_dir/data-backup"/* "$PULSE_DIR/data/" 2>/dev/null || true
|
|
fi
|
|
|
|
# Restore .env file if it was backed up
|
|
if [ -f "$temp_dir/.env-backup" ]; then
|
|
print_info "Restoring configuration..."
|
|
cp "$temp_dir/.env-backup" "$PULSE_DIR/.env"
|
|
chown "$PULSE_USER:$PULSE_USER" "$PULSE_DIR/.env"
|
|
chmod 600 "$PULSE_DIR/.env"
|
|
fi
|
|
|
|
# Cleanup
|
|
cd /
|
|
rm -rf "$temp_dir"
|
|
|
|
print_success "Installation files ready"
|
|
return 0
|
|
}
|
|
|
|
# Get current installed version
|
|
get_current_version() {
|
|
if [ -f "$PULSE_DIR/package.json" ]; then
|
|
grep '"version"' "$PULSE_DIR/package.json" | head -1 | sed -E 's/.*"version": "([^"]+)".*/\1/'
|
|
fi
|
|
}
|
|
|
|
# Check installation status
|
|
check_installation() {
|
|
local pulse_exists=false
|
|
local old_pulse_exists=false
|
|
local service_exists=false
|
|
|
|
[ -d "$PULSE_DIR" ] && pulse_exists=true
|
|
[ -d "$OLD_PULSE_DIR" ] && old_pulse_exists=true
|
|
# Check for any pulse-related service
|
|
(systemctl list-unit-files | grep -q "^$SERVICE_NAME" || \
|
|
systemctl list-unit-files | grep -q "^pulse-monitor.service" || \
|
|
systemctl list-unit-files | grep -q "^pulse-proxmox.service") && service_exists=true
|
|
|
|
if [ "$old_pulse_exists" = true ]; then
|
|
print_info "Old installation detected at $OLD_PULSE_DIR"
|
|
INSTALL_MODE="migrate"
|
|
elif [ "$pulse_exists" = true ] || [ "$service_exists" = true ]; then
|
|
local current_version=$(get_current_version)
|
|
if [ -n "$current_version" ]; then
|
|
print_info "Pulse v$current_version is installed"
|
|
else
|
|
print_info "Pulse is installed"
|
|
fi
|
|
|
|
if [ -n "$MODE_UPDATE" ]; then
|
|
INSTALL_MODE="update"
|
|
else
|
|
echo ""
|
|
echo "Choose an action:"
|
|
echo " 1) Update to latest version"
|
|
echo " 2) Remove Pulse"
|
|
echo " 3) Cancel"
|
|
echo ""
|
|
read -p "Your choice [1-3]: " choice
|
|
|
|
case $choice in
|
|
1) INSTALL_MODE="update" ;;
|
|
2) INSTALL_MODE="remove" ;;
|
|
3) print_info "Cancelled"; exit 0 ;;
|
|
*) print_error "Invalid choice"; exit 1 ;;
|
|
esac
|
|
fi
|
|
else
|
|
INSTALL_MODE="install"
|
|
print_info "Pulse is not installed"
|
|
fi
|
|
}
|
|
|
|
# Install system dependencies
|
|
install_dependencies() {
|
|
print_info "Checking system dependencies..."
|
|
|
|
# Update package lists quietly
|
|
apt-get update -qq || { print_error "Failed to update package lists"; exit 1; }
|
|
|
|
# Check and install missing dependencies
|
|
local deps="curl sudo gpg tar"
|
|
local missing_deps=""
|
|
|
|
for dep in $deps; do
|
|
if ! command -v $dep &> /dev/null; then
|
|
missing_deps="$missing_deps $dep"
|
|
fi
|
|
done
|
|
|
|
# Check for polkit separately since it's a package, not a command
|
|
if ! command -v pkexec &> /dev/null; then
|
|
missing_deps="$missing_deps policykit-1"
|
|
fi
|
|
|
|
if [ -n "$missing_deps" ]; then
|
|
print_info "Installing:$missing_deps"
|
|
apt-get install -y -qq $missing_deps || { print_error "Failed to install dependencies"; exit 1; }
|
|
fi
|
|
|
|
print_success "System dependencies ready"
|
|
}
|
|
|
|
# Setup Node.js
|
|
setup_node() {
|
|
if command -v node &> /dev/null; then
|
|
local current_version=$(node -v | sed 's/v//' | cut -d. -f1)
|
|
if [ "$current_version" -ge "$NODE_MAJOR_VERSION" ]; then
|
|
print_success "Node.js $(node -v) is installed"
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
print_info "Installing Node.js v$NODE_MAJOR_VERSION..."
|
|
|
|
# Install NodeSource repository
|
|
mkdir -p /etc/apt/keyrings
|
|
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
|
|
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR_VERSION.x nodistro main" > /etc/apt/sources.list.d/nodesource.list
|
|
|
|
apt-get update -qq || { print_error "Failed to update package lists"; exit 1; }
|
|
apt-get install -y -qq nodejs || { print_error "Failed to install Node.js"; exit 1; }
|
|
|
|
print_success "Node.js $(node -v) installed"
|
|
}
|
|
|
|
# Create pulse user
|
|
create_pulse_user() {
|
|
if id "$PULSE_USER" &>/dev/null; then
|
|
print_success "User '$PULSE_USER' exists"
|
|
else
|
|
print_info "Creating user '$PULSE_USER'..."
|
|
useradd -r -s /bin/false -d /nonexistent -U "$PULSE_USER" || {
|
|
print_error "Failed to create user"
|
|
exit 1
|
|
}
|
|
print_success "User created"
|
|
fi
|
|
}
|
|
|
|
# Set file permissions
|
|
set_permissions() {
|
|
print_info "Setting permissions..."
|
|
|
|
chown -R "$PULSE_USER:$PULSE_USER" "$PULSE_DIR"
|
|
chmod -R 755 "$PULSE_DIR"
|
|
|
|
# Ensure data directory exists
|
|
mkdir -p "$PULSE_DIR/data"
|
|
chown "$PULSE_USER:$PULSE_USER" "$PULSE_DIR/data"
|
|
chmod 755 "$PULSE_DIR/data"
|
|
}
|
|
|
|
# Configure environment
|
|
configure_environment() {
|
|
local env_file="$PULSE_DIR/.env"
|
|
if [ ! -f "$env_file" ]; then
|
|
cat > "$env_file" << EOF
|
|
NODE_ENV=production
|
|
PORT=7655
|
|
EOF
|
|
chown "$PULSE_USER:$PULSE_USER" "$env_file"
|
|
chmod 600 "$env_file"
|
|
fi
|
|
}
|
|
|
|
# Setup systemd service
|
|
setup_systemd_service() {
|
|
print_info "Configuring service..."
|
|
|
|
cat > "/etc/systemd/system/$SERVICE_NAME" << EOF
|
|
[Unit]
|
|
Description=Pulse Monitor for Proxmox VE
|
|
After=network.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
User=$PULSE_USER
|
|
WorkingDirectory=$PULSE_DIR
|
|
ExecStart=/usr/bin/node $PULSE_DIR/server/index.js
|
|
Restart=always
|
|
RestartSec=10
|
|
StandardOutput=journal
|
|
StandardError=journal
|
|
SyslogIdentifier=pulse-monitor
|
|
Environment="NODE_ENV=production"
|
|
Environment="PORT=7655"
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
EOF
|
|
|
|
systemctl daemon-reload
|
|
systemctl enable "$SERVICE_NAME" &>/dev/null
|
|
|
|
# Setup polkit rule for sudoless updates
|
|
setup_polkit_rule
|
|
|
|
systemctl start "$SERVICE_NAME"
|
|
|
|
# Wait a moment and check if service started
|
|
sleep 2
|
|
if systemctl is-active --quiet "$SERVICE_NAME"; then
|
|
print_success "Service started"
|
|
else
|
|
print_error "Service failed to start"
|
|
print_info "Check logs: journalctl -u $SERVICE_NAME -n 50"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Setup polkit rule for sudoless service management
|
|
setup_polkit_rule() {
|
|
print_info "Setting up polkit rule for automatic updates..."
|
|
|
|
# Note: polkit is required for sudoless updates in the web interface
|
|
# Without this, users would need to manually restart the service after updates
|
|
|
|
# Create polkit rules directory if it doesn't exist
|
|
mkdir -p /etc/polkit-1/rules.d
|
|
|
|
# Create the polkit rule
|
|
cat > /etc/polkit-1/rules.d/10-pulse-service.rules << 'EOF'
|
|
/* Allow pulse user to manage pulse.service without password */
|
|
polkit.addRule(function(action, subject) {
|
|
if ((action.id == "org.freedesktop.systemd1.manage-units" ||
|
|
action.id == "org.freedesktop.systemd1.manage-unit-files" ||
|
|
action.id == "org.freedesktop.systemd1.reload-daemon") &&
|
|
action.lookup("unit") == "pulse.service" &&
|
|
subject.user == "pulse") {
|
|
return polkit.Result.YES;
|
|
}
|
|
return polkit.Result.NOT_HANDLED;
|
|
});
|
|
EOF
|
|
|
|
# Set correct permissions
|
|
chmod 644 /etc/polkit-1/rules.d/10-pulse-service.rules
|
|
|
|
# Restart polkit to apply changes (don't fail if polkit isn't running)
|
|
if systemctl is-active --quiet polkit 2>/dev/null; then
|
|
systemctl restart polkit 2>/dev/null || true
|
|
fi
|
|
|
|
print_success "Polkit rule configured for automatic updates"
|
|
}
|
|
|
|
# Perform installation
|
|
perform_install() {
|
|
print_info "Installing Pulse..."
|
|
echo ""
|
|
|
|
install_dependencies
|
|
setup_node
|
|
create_pulse_user
|
|
|
|
# Determine target version
|
|
if [ -n "$SPECIFIED_VERSION_TAG" ]; then
|
|
TARGET_TAG="$SPECIFIED_VERSION_TAG"
|
|
if ! check_release_exists "$TARGET_TAG"; then
|
|
print_error "Version $TARGET_TAG does not exist"
|
|
exit 1
|
|
fi
|
|
else
|
|
TARGET_TAG=$(get_latest_release_tag)
|
|
if [ -z "$TARGET_TAG" ]; then
|
|
print_error "Could not determine latest version"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
download_and_extract_tarball "$TARGET_TAG" || exit 1
|
|
|
|
# Fix Express version if needed
|
|
print_info "Checking dependencies..."
|
|
cd "$PULSE_DIR"
|
|
if grep -q '"express": "4.19.2"' package.json; then
|
|
local current_express=$(npm list express --depth=0 2>/dev/null | grep express@ | sed 's/.*express@//' || echo "")
|
|
if [[ "$current_express" != "4.19.2" ]]; then
|
|
print_warning "Fixing Express version mismatch..."
|
|
rm -rf node_modules
|
|
npm install --omit=dev || {
|
|
print_error "Failed to install dependencies"
|
|
exit 1
|
|
}
|
|
fi
|
|
fi
|
|
|
|
set_permissions
|
|
configure_environment
|
|
setup_systemd_service
|
|
|
|
echo ""
|
|
print_success "Installation complete!"
|
|
}
|
|
|
|
# Perform update
|
|
perform_update() {
|
|
# Stop service
|
|
if systemctl is-active --quiet "$SERVICE_NAME"; then
|
|
print_info "Stopping service..."
|
|
systemctl stop "$SERVICE_NAME"
|
|
fi
|
|
|
|
# Determine target version
|
|
if [ -n "$SPECIFIED_VERSION_TAG" ]; then
|
|
TARGET_TAG="$SPECIFIED_VERSION_TAG"
|
|
if ! check_release_exists "$TARGET_TAG"; then
|
|
print_error "Version $TARGET_TAG does not exist"
|
|
exit 1
|
|
fi
|
|
else
|
|
TARGET_TAG=$(get_latest_release_tag)
|
|
if [ -z "$TARGET_TAG" ]; then
|
|
print_error "Could not determine latest version"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
local current_version=$(get_current_version)
|
|
if [ "$current_version" = "${TARGET_TAG#v}" ]; then
|
|
print_info "Already running latest version"
|
|
systemctl start "$SERVICE_NAME"
|
|
return 0
|
|
fi
|
|
|
|
print_info "Updating to $TARGET_TAG..."
|
|
echo ""
|
|
|
|
download_and_extract_tarball "$TARGET_TAG" || exit 1
|
|
|
|
# Fix Express version if needed
|
|
print_info "Checking dependencies..."
|
|
cd "$PULSE_DIR"
|
|
if grep -q '"express": "4.19.2"' package.json; then
|
|
local current_express=$(npm list express --depth=0 2>/dev/null | grep express@ | sed 's/.*express@//' || echo "")
|
|
if [[ "$current_express" != "4.19.2" ]]; then
|
|
print_warning "Fixing Express version mismatch..."
|
|
rm -rf node_modules
|
|
npm install --omit=dev || {
|
|
print_error "Failed to install dependencies"
|
|
exit 1
|
|
}
|
|
fi
|
|
fi
|
|
|
|
set_permissions
|
|
|
|
# Restart service
|
|
systemctl start "$SERVICE_NAME"
|
|
|
|
sleep 2
|
|
if systemctl is-active --quiet "$SERVICE_NAME"; then
|
|
echo ""
|
|
print_success "Update complete!"
|
|
else
|
|
print_error "Service failed to start after update"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Remove Pulse
|
|
perform_remove() {
|
|
print_warning "This will completely remove Pulse"
|
|
read -p "Are you sure? [y/N]: " confirm
|
|
|
|
if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
|
|
print_info "Cancelled"
|
|
exit 0
|
|
fi
|
|
|
|
echo ""
|
|
|
|
# Stop and disable service
|
|
if systemctl is-active --quiet "$SERVICE_NAME"; then
|
|
print_info "Stopping service..."
|
|
systemctl stop "$SERVICE_NAME"
|
|
fi
|
|
systemctl disable "$SERVICE_NAME" &>/dev/null || true
|
|
rm -f "/etc/systemd/system/$SERVICE_NAME"
|
|
systemctl daemon-reload
|
|
|
|
# Remove directories
|
|
[ -d "$PULSE_DIR" ] && rm -rf "$PULSE_DIR"
|
|
[ -d "$OLD_PULSE_DIR" ] && rm -rf "$OLD_PULSE_DIR"
|
|
|
|
print_success "Pulse has been removed"
|
|
}
|
|
|
|
# Migrate from old installation
|
|
perform_migration() {
|
|
print_info "Migrating old installation..."
|
|
|
|
# Stop old service (could be either pulse-proxmox.service or pulse-monitor.service)
|
|
if systemctl is-active --quiet "pulse-proxmox.service"; then
|
|
systemctl stop "pulse-proxmox.service"
|
|
fi
|
|
if systemctl is-active --quiet "pulse-monitor.service"; then
|
|
systemctl stop "pulse-monitor.service"
|
|
fi
|
|
systemctl disable "pulse-proxmox.service" &>/dev/null || true
|
|
systemctl disable "pulse-monitor.service" &>/dev/null || true
|
|
|
|
# Backup old data
|
|
local backup_dir="/tmp/pulse-migration-$$"
|
|
mkdir -p "$backup_dir"
|
|
|
|
if [ -d "$OLD_PULSE_DIR/data" ]; then
|
|
cp -r "$OLD_PULSE_DIR/data" "$backup_dir/"
|
|
fi
|
|
|
|
# Backup old .env file if it exists
|
|
if [ -f "$OLD_PULSE_DIR/.env" ]; then
|
|
cp "$OLD_PULSE_DIR/.env" "$backup_dir/.env"
|
|
fi
|
|
|
|
# Remove old installation
|
|
rm -rf "$OLD_PULSE_DIR"
|
|
rm -f "/etc/systemd/system/pulse-proxmox.service"
|
|
rm -f "/etc/systemd/system/pulse-monitor.service"
|
|
|
|
# Perform fresh install
|
|
INSTALL_MODE="install"
|
|
perform_install
|
|
|
|
# Restore old data
|
|
if [ -d "$backup_dir/data" ]; then
|
|
print_info "Restoring data..."
|
|
cp -r "$backup_dir/data"/* "$PULSE_DIR/data/" 2>/dev/null || true
|
|
chown -R "$PULSE_USER:$PULSE_USER" "$PULSE_DIR/data"
|
|
fi
|
|
|
|
# Restore old .env file
|
|
if [ -f "$backup_dir/.env" ]; then
|
|
print_info "Restoring configuration..."
|
|
cp "$backup_dir/.env" "$PULSE_DIR/.env"
|
|
chown "$PULSE_USER:$PULSE_USER" "$PULSE_DIR/.env"
|
|
chmod 600 "$PULSE_DIR/.env"
|
|
fi
|
|
|
|
rm -rf "$backup_dir"
|
|
}
|
|
|
|
# Show final instructions
|
|
show_final_instructions() {
|
|
local ip=$(hostname -I | awk '{print $1}')
|
|
echo ""
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo -e "Access Pulse: \033[1;36mhttp://${ip}:7655\033[0m"
|
|
echo ""
|
|
echo "Useful commands:"
|
|
echo " • systemctl status $SERVICE_NAME"
|
|
echo " • journalctl -u $SERVICE_NAME -f"
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo ""
|
|
}
|
|
|
|
# Main execution
|
|
main() {
|
|
check_root
|
|
self_update_check
|
|
print_welcome
|
|
check_installation
|
|
|
|
case "$INSTALL_MODE" in
|
|
install)
|
|
perform_install
|
|
show_final_instructions
|
|
;;
|
|
update)
|
|
perform_update
|
|
show_final_instructions
|
|
;;
|
|
remove)
|
|
perform_remove
|
|
;;
|
|
migrate)
|
|
perform_migration
|
|
show_final_instructions
|
|
;;
|
|
*)
|
|
print_error "Invalid operation"
|
|
exit 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# Run main function
|
|
main |