mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-02-18 00:17:39 +01:00
Improve installer UX with pauses and popups on failure
Fixes #755. Adds interactive pauses and graphical popups (where available) to installer scripts when critical errors occur, ensuring troubleshooting guides are readable. Also clarifies 'build from source' instructions.
This commit is contained in:
@@ -1004,6 +1004,11 @@ func (r *Router) setupRoutes() {
|
||||
r.mux.HandleFunc("/download/pulse-host-agent", r.handleDownloadHostAgent)
|
||||
r.mux.HandleFunc("/download/pulse-host-agent.sha256", r.handleDownloadHostAgent)
|
||||
|
||||
// Unified Agent endpoints
|
||||
r.mux.HandleFunc("/install.sh", r.handleDownloadUnifiedInstallScript)
|
||||
r.mux.HandleFunc("/install.ps1", r.handleDownloadUnifiedInstallScriptPS)
|
||||
r.mux.HandleFunc("/download/pulse-agent", r.handleDownloadUnifiedAgent)
|
||||
|
||||
r.mux.HandleFunc("/api/agent/version", r.handleAgentVersion)
|
||||
r.mux.HandleFunc("/api/server/info", r.handleServerInfo)
|
||||
|
||||
@@ -1339,6 +1344,9 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
"/uninstall-host-agent.sh", // Host agent uninstall script must be public
|
||||
"/uninstall-host-agent.ps1", // Host agent uninstall script must be public
|
||||
"/download/pulse-host-agent", // Host agent binary download should not require auth
|
||||
"/install.sh", // Unified agent installer
|
||||
"/install.ps1", // Unified agent Windows installer
|
||||
"/download/pulse-agent", // Unified agent binary
|
||||
"/api/agent/version", // Agent update checks need to work before auth
|
||||
"/api/server/info", // Server info for installer script
|
||||
"/api/install/install-sensor-proxy.sh", // Temperature proxy installer fallback
|
||||
@@ -1364,7 +1372,10 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
req.URL.Path != "/install-container-agent.sh" &&
|
||||
req.URL.Path != "/install-host-agent.sh" &&
|
||||
req.URL.Path != "/install-host-agent.ps1" &&
|
||||
req.URL.Path != "/uninstall-host-agent.ps1"
|
||||
req.URL.Path != "/install-host-agent.ps1" &&
|
||||
req.URL.Path != "/uninstall-host-agent.ps1" &&
|
||||
req.URL.Path != "/install.sh" &&
|
||||
req.URL.Path != "/install.ps1"
|
||||
|
||||
isStaticAsset := strings.HasPrefix(req.URL.Path, "/assets/") ||
|
||||
strings.HasPrefix(req.URL.Path, "/@vite/") ||
|
||||
@@ -1508,7 +1519,9 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
path.Clean(req.URL.Path) == "/install-host-agent.sh" ||
|
||||
path.Clean(req.URL.Path) == "/install-host-agent.ps1" ||
|
||||
path.Clean(req.URL.Path) == "/uninstall-host-agent.sh" ||
|
||||
path.Clean(req.URL.Path) == "/uninstall-host-agent.ps1" {
|
||||
path.Clean(req.URL.Path) == "/uninstall-host-agent.ps1" ||
|
||||
path.Clean(req.URL.Path) == "/install.sh" ||
|
||||
path.Clean(req.URL.Path) == "/install.ps1" {
|
||||
// Use the mux for API and special routes
|
||||
r.mux.ServeHTTP(w, req)
|
||||
} else {
|
||||
@@ -3522,7 +3535,7 @@ func (r *Router) handleDownloadHostAgent(w http.ResponseWriter, req *http.Reques
|
||||
errorMsg.WriteString(fmt.Sprintf("Host agent binary not found for %s/%s\n\n", platformParam, archParam))
|
||||
errorMsg.WriteString("Troubleshooting:\n")
|
||||
errorMsg.WriteString("1. If running in Docker: Rebuild the Docker image to include all platform binaries\n")
|
||||
errorMsg.WriteString("2. If running bare metal: Run 'scripts/build-release.sh' to build all platform binaries\n")
|
||||
errorMsg.WriteString("2. If running from source: Run 'scripts/build-release.sh' to build all platform binaries\n")
|
||||
errorMsg.WriteString("3. Build from source:\n")
|
||||
errorMsg.WriteString(fmt.Sprintf(" GOOS=%s GOARCH=%s go build -o pulse-host-agent-%s-%s ./cmd/pulse-host-agent\n", platformParam, archParam, platformParam, archParam))
|
||||
errorMsg.WriteString(fmt.Sprintf(" sudo mv pulse-host-agent-%s-%s /opt/pulse/bin/\n\n", platformParam, archParam))
|
||||
|
||||
@@ -546,6 +546,24 @@ if [ "$UNINSTALL" = true ]; then
|
||||
echo "✓ Unraid startup script removed"
|
||||
fi
|
||||
|
||||
# Remove Synology Upstart config
|
||||
if [ -f "/etc/init/pulse-docker-agent.conf" ]; then
|
||||
initctl stop pulse-docker-agent 2>/dev/null || true
|
||||
rm -f "/etc/init/pulse-docker-agent.conf"
|
||||
echo "✓ Synology Upstart config removed"
|
||||
fi
|
||||
|
||||
# Stop and remove launchd service (macOS)
|
||||
if [[ "$(uname -s)" == "Darwin" ]]; then
|
||||
LAUNCHD_PLIST="/Library/LaunchDaemons/com.pulse.docker-agent.plist"
|
||||
if [[ -f "$LAUNCHD_PLIST" ]]; then
|
||||
echo "Stopping launchd service..."
|
||||
launchctl unload "$LAUNCHD_PLIST" 2>/dev/null || true
|
||||
rm -f "$LAUNCHD_PLIST"
|
||||
echo "✓ Launchd service removed"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Remove log file
|
||||
if [ -f "$LOG_PATH" ]; then
|
||||
rm -f "$LOG_PATH"
|
||||
@@ -774,6 +792,15 @@ if download_agent_binary "$DOWNLOAD_URL" "$DOWNLOAD_URL_BASE"; then
|
||||
else
|
||||
log_warn 'Failed to download agent binary'
|
||||
log_warn "Ensure the Pulse server is reachable at $PRIMARY_URL"
|
||||
|
||||
if common::is_interactive; then
|
||||
echo ""
|
||||
if [[ -t 0 ]]; then
|
||||
read -p "Press Enter to exit..."
|
||||
elif [[ -e /dev/tty ]]; then
|
||||
read -p "Press Enter to exit..." < /dev/tty
|
||||
fi
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -942,6 +969,119 @@ EOF
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Check if this is Synology DSM (has /usr/syno/etc/rc.sysv)
|
||||
if [ -d /usr/syno/etc/rc.sysv ]; then
|
||||
log_info 'Detected Synology DSM environment'
|
||||
|
||||
UPSTART_CONF="/etc/init/pulse-docker-agent.conf"
|
||||
|
||||
cat > "$UPSTART_CONF" <<EOF
|
||||
description "Pulse Docker Agent"
|
||||
author "Pulse"
|
||||
|
||||
start on syno.network.ready
|
||||
stop on runlevel [06]
|
||||
|
||||
respawn
|
||||
respawn limit 5 10
|
||||
|
||||
env PULSE_URL="$PRIMARY_URL"
|
||||
env PULSE_TOKEN="$PRIMARY_TOKEN"
|
||||
env PULSE_TARGETS="$JOINED_TARGETS"
|
||||
env PULSE_INSECURE_SKIP_VERIFY="$PRIMARY_INSECURE"
|
||||
|
||||
exec $AGENT_PATH --url "$PRIMARY_URL" --interval "$INTERVAL"$NO_AUTO_UPDATE_FLAG
|
||||
EOF
|
||||
|
||||
log_success "Created Upstart config: $UPSTART_CONF"
|
||||
|
||||
log_info 'Starting service'
|
||||
initctl stop pulse-docker-agent 2>/dev/null || true
|
||||
initctl start pulse-docker-agent
|
||||
|
||||
log_header 'Installation complete'
|
||||
log_info 'Agent service enabled and started via Upstart'
|
||||
log_info 'Check status : initctl status pulse-docker-agent'
|
||||
log_info 'Follow logs : tail -f /var/log/upstart/pulse-docker-agent.log'
|
||||
log_info 'Host visible in Pulse : ~30 seconds'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Check if this is macOS (Darwin)
|
||||
if [[ "$(uname -s)" == "Darwin" ]]; then
|
||||
log_info 'Detected macOS environment'
|
||||
|
||||
LAUNCHD_PLIST="/Library/LaunchDaemons/com.pulse.docker-agent.plist"
|
||||
|
||||
# Construct environment variables dict
|
||||
ENV_DICT=""
|
||||
if [[ -n "$PRIMARY_URL" ]]; then
|
||||
ENV_DICT="$ENV_DICT
|
||||
<key>PULSE_URL</key>
|
||||
<string>$PRIMARY_URL</string>"
|
||||
fi
|
||||
if [[ -n "$PRIMARY_TOKEN" ]]; then
|
||||
ENV_DICT="$ENV_DICT
|
||||
<key>PULSE_TOKEN</key>
|
||||
<string>$PRIMARY_TOKEN</string>"
|
||||
fi
|
||||
if [[ -n "$JOINED_TARGETS" ]]; then
|
||||
ENV_DICT="$ENV_DICT
|
||||
<key>PULSE_TARGETS</key>
|
||||
<string>$JOINED_TARGETS</string>"
|
||||
fi
|
||||
if [[ -n "$PRIMARY_INSECURE" ]]; then
|
||||
ENV_DICT="$ENV_DICT
|
||||
<key>PULSE_INSECURE_SKIP_VERIFY</key>
|
||||
<string>$PRIMARY_INSECURE</string>"
|
||||
fi
|
||||
|
||||
cat > "$LAUNCHD_PLIST" <<EOF
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>com.pulse.docker-agent</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>$AGENT_PATH</string>
|
||||
<string>--url</string>
|
||||
<string>$PRIMARY_URL</string>
|
||||
<string>--interval</string>
|
||||
<string>$INTERVAL</string>
|
||||
<string>--no-auto-update</string>
|
||||
</array>
|
||||
<key>EnvironmentVariables</key>
|
||||
<dict>$ENV_DICT
|
||||
</dict>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
<key>KeepAlive</key>
|
||||
<true/>
|
||||
<key>StandardOutPath</key>
|
||||
<string>/var/log/pulse-docker-agent.log</string>
|
||||
<key>StandardErrorPath</key>
|
||||
<string>/var/log/pulse-docker-agent.log</string>
|
||||
</dict>
|
||||
</plist>
|
||||
EOF
|
||||
|
||||
chmod 644 "$LAUNCHD_PLIST"
|
||||
log_success "Created launchd plist: $LAUNCHD_PLIST"
|
||||
|
||||
log_info 'Starting service'
|
||||
launchctl unload "$LAUNCHD_PLIST" 2>/dev/null || true
|
||||
launchctl load -w "$LAUNCHD_PLIST"
|
||||
|
||||
log_header 'Installation complete'
|
||||
log_info 'Agent service enabled and started via launchd'
|
||||
log_info 'Check status : sudo launchctl list com.pulse.docker-agent'
|
||||
log_info 'Follow logs : tail -f /var/log/pulse-docker-agent.log'
|
||||
log_info 'Host visible in Pulse : ~30 seconds'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
log_info 'Manual startup environment detected'
|
||||
log_info "Binary location : $AGENT_PATH"
|
||||
log_info 'Start manually with :'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Generated file. Do not edit.
|
||||
# Bundled on: 2025-11-25T09:29:44Z
|
||||
# Bundled on: 2025-11-25T11:15:48Z
|
||||
# Manifest: scripts/bundle.manifest
|
||||
|
||||
# === Begin: scripts/lib/common.sh ===
|
||||
@@ -111,6 +111,16 @@ common::fail() {
|
||||
done
|
||||
local message="${message_parts[*]}"
|
||||
common::log_error "${message}"
|
||||
|
||||
if common::is_interactive; then
|
||||
echo ""
|
||||
if [[ -t 0 ]]; then
|
||||
read -p "Press Enter to exit..."
|
||||
elif [[ -e /dev/tty ]]; then
|
||||
read -p "Press Enter to exit..." < /dev/tty
|
||||
fi
|
||||
fi
|
||||
|
||||
exit "${exit_code}"
|
||||
}
|
||||
|
||||
@@ -1509,6 +1519,24 @@ if [ "$UNINSTALL" = true ]; then
|
||||
echo "✓ Unraid startup script removed"
|
||||
fi
|
||||
|
||||
# Remove Synology Upstart config
|
||||
if [ -f "/etc/init/pulse-docker-agent.conf" ]; then
|
||||
initctl stop pulse-docker-agent 2>/dev/null || true
|
||||
rm -f "/etc/init/pulse-docker-agent.conf"
|
||||
echo "✓ Synology Upstart config removed"
|
||||
fi
|
||||
|
||||
# Stop and remove launchd service (macOS)
|
||||
if [[ "$(uname -s)" == "Darwin" ]]; then
|
||||
LAUNCHD_PLIST="/Library/LaunchDaemons/com.pulse.docker-agent.plist"
|
||||
if [[ -f "$LAUNCHD_PLIST" ]]; then
|
||||
echo "Stopping launchd service..."
|
||||
launchctl unload "$LAUNCHD_PLIST" 2>/dev/null || true
|
||||
rm -f "$LAUNCHD_PLIST"
|
||||
echo "✓ Launchd service removed"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Remove log file
|
||||
if [ -f "$LOG_PATH" ]; then
|
||||
rm -f "$LOG_PATH"
|
||||
@@ -1737,6 +1765,15 @@ if download_agent_binary "$DOWNLOAD_URL" "$DOWNLOAD_URL_BASE"; then
|
||||
else
|
||||
log_warn 'Failed to download agent binary'
|
||||
log_warn "Ensure the Pulse server is reachable at $PRIMARY_URL"
|
||||
|
||||
if common::is_interactive; then
|
||||
echo ""
|
||||
if [[ -t 0 ]]; then
|
||||
read -p "Press Enter to exit..."
|
||||
elif [[ -e /dev/tty ]]; then
|
||||
read -p "Press Enter to exit..." < /dev/tty
|
||||
fi
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -1905,6 +1942,119 @@ EOF
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Check if this is Synology DSM (has /usr/syno/etc/rc.sysv)
|
||||
if [ -d /usr/syno/etc/rc.sysv ]; then
|
||||
log_info 'Detected Synology DSM environment'
|
||||
|
||||
UPSTART_CONF="/etc/init/pulse-docker-agent.conf"
|
||||
|
||||
cat > "$UPSTART_CONF" <<EOF
|
||||
description "Pulse Docker Agent"
|
||||
author "Pulse"
|
||||
|
||||
start on syno.network.ready
|
||||
stop on runlevel [06]
|
||||
|
||||
respawn
|
||||
respawn limit 5 10
|
||||
|
||||
env PULSE_URL="$PRIMARY_URL"
|
||||
env PULSE_TOKEN="$PRIMARY_TOKEN"
|
||||
env PULSE_TARGETS="$JOINED_TARGETS"
|
||||
env PULSE_INSECURE_SKIP_VERIFY="$PRIMARY_INSECURE"
|
||||
|
||||
exec $AGENT_PATH --url "$PRIMARY_URL" --interval "$INTERVAL"$NO_AUTO_UPDATE_FLAG
|
||||
EOF
|
||||
|
||||
log_success "Created Upstart config: $UPSTART_CONF"
|
||||
|
||||
log_info 'Starting service'
|
||||
initctl stop pulse-docker-agent 2>/dev/null || true
|
||||
initctl start pulse-docker-agent
|
||||
|
||||
log_header 'Installation complete'
|
||||
log_info 'Agent service enabled and started via Upstart'
|
||||
log_info 'Check status : initctl status pulse-docker-agent'
|
||||
log_info 'Follow logs : tail -f /var/log/upstart/pulse-docker-agent.log'
|
||||
log_info 'Host visible in Pulse : ~30 seconds'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Check if this is macOS (Darwin)
|
||||
if [[ "$(uname -s)" == "Darwin" ]]; then
|
||||
log_info 'Detected macOS environment'
|
||||
|
||||
LAUNCHD_PLIST="/Library/LaunchDaemons/com.pulse.docker-agent.plist"
|
||||
|
||||
# Construct environment variables dict
|
||||
ENV_DICT=""
|
||||
if [[ -n "$PRIMARY_URL" ]]; then
|
||||
ENV_DICT="$ENV_DICT
|
||||
<key>PULSE_URL</key>
|
||||
<string>$PRIMARY_URL</string>"
|
||||
fi
|
||||
if [[ -n "$PRIMARY_TOKEN" ]]; then
|
||||
ENV_DICT="$ENV_DICT
|
||||
<key>PULSE_TOKEN</key>
|
||||
<string>$PRIMARY_TOKEN</string>"
|
||||
fi
|
||||
if [[ -n "$JOINED_TARGETS" ]]; then
|
||||
ENV_DICT="$ENV_DICT
|
||||
<key>PULSE_TARGETS</key>
|
||||
<string>$JOINED_TARGETS</string>"
|
||||
fi
|
||||
if [[ -n "$PRIMARY_INSECURE" ]]; then
|
||||
ENV_DICT="$ENV_DICT
|
||||
<key>PULSE_INSECURE_SKIP_VERIFY</key>
|
||||
<string>$PRIMARY_INSECURE</string>"
|
||||
fi
|
||||
|
||||
cat > "$LAUNCHD_PLIST" <<EOF
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>com.pulse.docker-agent</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>$AGENT_PATH</string>
|
||||
<string>--url</string>
|
||||
<string>$PRIMARY_URL</string>
|
||||
<string>--interval</string>
|
||||
<string>$INTERVAL</string>
|
||||
<string>--no-auto-update</string>
|
||||
</array>
|
||||
<key>EnvironmentVariables</key>
|
||||
<dict>$ENV_DICT
|
||||
</dict>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
<key>KeepAlive</key>
|
||||
<true/>
|
||||
<key>StandardOutPath</key>
|
||||
<string>/var/log/pulse-docker-agent.log</string>
|
||||
<key>StandardErrorPath</key>
|
||||
<string>/var/log/pulse-docker-agent.log</string>
|
||||
</dict>
|
||||
</plist>
|
||||
EOF
|
||||
|
||||
chmod 644 "$LAUNCHD_PLIST"
|
||||
log_success "Created launchd plist: $LAUNCHD_PLIST"
|
||||
|
||||
log_info 'Starting service'
|
||||
launchctl unload "$LAUNCHD_PLIST" 2>/dev/null || true
|
||||
launchctl load -w "$LAUNCHD_PLIST"
|
||||
|
||||
log_header 'Installation complete'
|
||||
log_info 'Agent service enabled and started via launchd'
|
||||
log_info 'Check status : sudo launchctl list com.pulse.docker-agent'
|
||||
log_info 'Follow logs : tail -f /var/log/pulse-docker-agent.log'
|
||||
log_info 'Host visible in Pulse : ~30 seconds'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
log_info 'Manual startup environment detected'
|
||||
log_info "Binary location : $AGENT_PATH"
|
||||
log_info 'Start manually with :'
|
||||
|
||||
@@ -391,6 +391,18 @@ try {
|
||||
$manualCommand = "& `"$agentPath`" $($agentArgs -join ' ')"
|
||||
} catch {
|
||||
PulseError "Failed to download agent: $_"
|
||||
|
||||
# Try to show a popup if running in a GUI environment
|
||||
try {
|
||||
Add-Type -AssemblyName System.Windows.Forms
|
||||
[System.Windows.Forms.MessageBox]::Show("Failed to download agent.`n`n$_", "Pulse Installation Failed", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error) | Out-Null
|
||||
} catch {
|
||||
# Ignore if GUI not available
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Press Enter to exit..." -ForegroundColor Yellow
|
||||
Read-Host
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
||||
@@ -422,6 +422,13 @@ if [[ "$DOWNLOAD_SUCCESS" == false ]]; then
|
||||
echo "4. Check firewall/network settings blocking the connection"
|
||||
echo ""
|
||||
rm -f "$TEMP_BINARY"
|
||||
|
||||
echo ""
|
||||
if [[ -t 0 ]]; then
|
||||
read -p "Press Enter to exit..."
|
||||
elif [[ -e /dev/tty ]]; then
|
||||
read -p "Press Enter to exit..." < /dev/tty
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
91
scripts/install.ps1
Normal file
91
scripts/install.ps1
Normal file
@@ -0,0 +1,91 @@
|
||||
# Pulse Unified Agent Installer (Windows)
|
||||
# Usage:
|
||||
# irm http://pulse/install.ps1 | iex
|
||||
# $env:PULSE_URL="..."; $env:PULSE_TOKEN="..."; irm ... | iex
|
||||
|
||||
param (
|
||||
[string]$Url = $env:PULSE_URL,
|
||||
[string]$Token = $env:PULSE_TOKEN,
|
||||
[string]$Interval = "30s",
|
||||
[bool]$EnableHost = $true,
|
||||
[bool]$EnableDocker = $false,
|
||||
[bool]$Insecure = $false,
|
||||
[bool]$Uninstall = $false
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$AgentName = "PulseAgent"
|
||||
$BinaryName = "pulse-agent.exe"
|
||||
$InstallDir = "C:\Program Files\Pulse"
|
||||
$LogFile = "$env:ProgramData\Pulse\pulse-agent.log"
|
||||
|
||||
# --- Uninstall Logic ---
|
||||
if ($Uninstall) {
|
||||
Write-Host "Uninstalling $AgentName..." -ForegroundColor Cyan
|
||||
|
||||
if (Get-Service $AgentName -ErrorAction SilentlyContinue) {
|
||||
Stop-Service $AgentName -Force -ErrorAction SilentlyContinue
|
||||
sc.exe delete $AgentName | Out-Null
|
||||
}
|
||||
|
||||
Remove-Item "$InstallDir\$BinaryName" -Force -ErrorAction SilentlyContinue
|
||||
Write-Host "Uninstallation complete." -ForegroundColor Green
|
||||
Exit 0
|
||||
}
|
||||
|
||||
# --- Validation ---
|
||||
if ([string]::IsNullOrWhiteSpace($Url) -or [string]::IsNullOrWhiteSpace($Token)) {
|
||||
Write-Error "Missing required parameters: Url and Token. Set PULSE_URL/PULSE_TOKEN env vars or pass arguments."
|
||||
Exit 1
|
||||
}
|
||||
|
||||
# --- Download ---
|
||||
$DownloadUrl = "$Url/download/pulse-agent?os=windows&arch=amd64"
|
||||
Write-Host "Downloading agent from $DownloadUrl..." -ForegroundColor Cyan
|
||||
|
||||
if (-not (Test-Path $InstallDir)) {
|
||||
New-Item -ItemType Directory -Force -Path $InstallDir | Out-Null
|
||||
}
|
||||
|
||||
$DestPath = "$InstallDir\$BinaryName"
|
||||
try {
|
||||
Invoke-WebRequest -Uri $DownloadUrl -OutFile $DestPath -UseBasicParsing
|
||||
} catch {
|
||||
Write-Host "Failed to download agent: $_" -ForegroundColor Red
|
||||
|
||||
# Try to show a popup if running in a GUI environment
|
||||
try {
|
||||
Add-Type -AssemblyName System.Windows.Forms
|
||||
[System.Windows.Forms.MessageBox]::Show("Failed to download agent.`n`n$_", "Pulse Installation Failed", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error) | Out-Null
|
||||
} catch {
|
||||
# Ignore if GUI not available
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Press Enter to exit..." -ForegroundColor Yellow
|
||||
Read-Host
|
||||
Exit 1
|
||||
}
|
||||
|
||||
# --- Service Installation ---
|
||||
Write-Host "Configuring Windows Service..." -ForegroundColor Cyan
|
||||
|
||||
if (Get-Service $AgentName -ErrorAction SilentlyContinue) {
|
||||
Stop-Service $AgentName -Force -ErrorAction SilentlyContinue
|
||||
sc.exe delete $AgentName | Out-Null
|
||||
Start-Sleep -Seconds 2
|
||||
}
|
||||
|
||||
$Args = "--url `"$Url`" --token `"$Token`" --interval `"$Interval`" --enable-host=$EnableHost --enable-docker=$EnableDocker --insecure=$Insecure"
|
||||
$BinPath = "`"$DestPath`" $Args"
|
||||
|
||||
# Create Service
|
||||
sc.exe create $AgentName binPath= $BinPath start= auto displayname= "Pulse Unified Agent" | Out-Null
|
||||
sc.exe description $AgentName "Pulse Unified Agent for Host and Docker monitoring" | Out-Null
|
||||
sc.exe failure $AgentName reset= 86400 actions= restart/5000/restart/5000/restart/5000 | Out-Null
|
||||
|
||||
Start-Service $AgentName
|
||||
|
||||
Write-Host "Installation complete." -ForegroundColor Green
|
||||
Write-Host "Service: $AgentName"
|
||||
Write-Host "Logs: $LogFile"
|
||||
235
scripts/install.sh
Normal file
235
scripts/install.sh
Normal file
@@ -0,0 +1,235 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Pulse Unified Agent Installer
|
||||
# Supports: Linux (systemd), macOS (launchd), Synology (upstart)
|
||||
#
|
||||
# Usage:
|
||||
# curl -fsSL http://pulse/install.sh | bash -s -- --url http://pulse --token <token> [options]
|
||||
#
|
||||
# Options:
|
||||
# --enable-host Enable host metrics (default: true)
|
||||
# --enable-docker Enable docker metrics (default: false)
|
||||
# --interval <dur> Reporting interval (default: 30s)
|
||||
# --uninstall Remove the agent
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# --- Configuration ---
|
||||
AGENT_NAME="pulse-agent"
|
||||
BINARY_NAME="pulse-agent"
|
||||
INSTALL_DIR="/usr/local/bin"
|
||||
LOG_FILE="/var/log/${AGENT_NAME}.log"
|
||||
|
||||
# Defaults
|
||||
PULSE_URL=""
|
||||
PULSE_TOKEN=""
|
||||
INTERVAL="30s"
|
||||
ENABLE_HOST="true"
|
||||
ENABLE_DOCKER="false"
|
||||
UNINSTALL="false"
|
||||
INSECURE="false"
|
||||
|
||||
# --- Helper Functions ---
|
||||
log_info() { printf "[INFO] %s\n" "$1"; }
|
||||
log_warn() { printf "[WARN] %s\n" "$1"; }
|
||||
log_error() { printf "[ERROR] %s\n" "$1"; }
|
||||
fail() {
|
||||
log_error "$1"
|
||||
if [[ -t 0 ]]; then
|
||||
read -p "Press Enter to exit..."
|
||||
elif [[ -e /dev/tty ]]; then
|
||||
read -p "Press Enter to exit..." < /dev/tty
|
||||
fi
|
||||
exit 1
|
||||
}
|
||||
|
||||
# --- Parse Arguments ---
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--url) PULSE_URL="$2"; shift 2 ;;
|
||||
--token) PULSE_TOKEN="$2"; shift 2 ;;
|
||||
--interval) INTERVAL="$2"; shift 2 ;;
|
||||
--enable-host) ENABLE_HOST="true"; shift ;;
|
||||
--disable-host) ENABLE_HOST="false"; shift ;;
|
||||
--enable-docker) ENABLE_DOCKER="true"; shift ;;
|
||||
--disable-docker) ENABLE_DOCKER="false"; shift ;;
|
||||
--insecure) INSECURE="true"; shift ;;
|
||||
--uninstall) UNINSTALL="true"; shift ;;
|
||||
*) fail "Unknown argument: $1" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# --- Uninstall Logic ---
|
||||
if [[ "$UNINSTALL" == "true" ]]; then
|
||||
log_info "Uninstalling ${AGENT_NAME}..."
|
||||
|
||||
# Systemd
|
||||
if command -v systemctl >/dev/null 2>&1; then
|
||||
systemctl stop "${AGENT_NAME}" 2>/dev/null || true
|
||||
systemctl disable "${AGENT_NAME}" 2>/dev/null || true
|
||||
rm -f "/etc/systemd/system/${AGENT_NAME}.service"
|
||||
systemctl daemon-reload 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Launchd (macOS)
|
||||
if [[ "$(uname -s)" == "Darwin" ]]; then
|
||||
PLIST="/Library/LaunchDaemons/com.pulse.agent.plist"
|
||||
launchctl unload "$PLIST" 2>/dev/null || true
|
||||
rm -f "$PLIST"
|
||||
fi
|
||||
|
||||
# Upstart (Synology)
|
||||
if [[ -f "/etc/init/${AGENT_NAME}.conf" ]]; then
|
||||
initctl stop "${AGENT_NAME}" 2>/dev/null || true
|
||||
rm -f "/etc/init/${AGENT_NAME}.conf"
|
||||
fi
|
||||
|
||||
rm -f "${INSTALL_DIR}/${BINARY_NAME}"
|
||||
log_info "Uninstallation complete."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# --- Validation ---
|
||||
if [[ -z "$PULSE_URL" || -z "$PULSE_TOKEN" ]]; then
|
||||
fail "Missing required arguments: --url and --token"
|
||||
fi
|
||||
|
||||
# --- Download ---
|
||||
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
|
||||
ARCH=$(uname -m)
|
||||
|
||||
case "$ARCH" in
|
||||
x86_64) ARCH="amd64" ;;
|
||||
aarch64|arm64) ARCH="arm64" ;;
|
||||
*) fail "Unsupported architecture: $ARCH" ;;
|
||||
esac
|
||||
|
||||
DOWNLOAD_URL="${PULSE_URL}/download/${BINARY_NAME}?os=${OS}&arch=${ARCH}"
|
||||
log_info "Downloading agent from ${DOWNLOAD_URL}..."
|
||||
|
||||
# Create temp file
|
||||
TMP_BIN=$(mktemp)
|
||||
chmod +x "$TMP_BIN"
|
||||
|
||||
CURL_ARGS="-fsSL"
|
||||
if [[ "$INSECURE" == "true" ]]; then CURL_ARGS="-k $CURL_ARGS"; fi
|
||||
|
||||
if ! curl $CURL_ARGS -o "$TMP_BIN" "$DOWNLOAD_URL"; then
|
||||
fail "Download failed. Check URL and connectivity."
|
||||
fi
|
||||
|
||||
# Install Binary
|
||||
log_info "Installing binary to ${INSTALL_DIR}/${BINARY_NAME}..."
|
||||
mkdir -p "$INSTALL_DIR"
|
||||
mv "$TMP_BIN" "${INSTALL_DIR}/${BINARY_NAME}"
|
||||
|
||||
# --- Service Installation ---
|
||||
|
||||
# 1. macOS (Launchd)
|
||||
if [[ "$OS" == "darwin" ]]; then
|
||||
PLIST="/Library/LaunchDaemons/com.pulse.agent.plist"
|
||||
log_info "Configuring Launchd service at $PLIST..."
|
||||
|
||||
cat > "$PLIST" <<EOF
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>com.pulse.agent</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>${INSTALL_DIR}/${BINARY_NAME}</string>
|
||||
<string>--url</string>
|
||||
<string>${PULSE_URL}</string>
|
||||
<string>--token</string>
|
||||
<string>${PULSE_TOKEN}</string>
|
||||
<string>--interval</string>
|
||||
<string>${INTERVAL}</string>
|
||||
<string>--enable-host=${ENABLE_HOST}</string>
|
||||
<string>--enable-docker=${ENABLE_DOCKER}</string>
|
||||
<string>--insecure=${INSECURE}</string>
|
||||
</array>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
<key>KeepAlive</key>
|
||||
<true/>
|
||||
<key>StandardOutPath</key>
|
||||
<string>${LOG_FILE}</string>
|
||||
<key>StandardErrorPath</key>
|
||||
<string>${LOG_FILE}</string>
|
||||
</dict>
|
||||
</plist>
|
||||
EOF
|
||||
chmod 644 "$PLIST"
|
||||
launchctl unload "$PLIST" 2>/dev/null || true
|
||||
launchctl load -w "$PLIST"
|
||||
log_info "Service started."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 2. Synology (Upstart)
|
||||
if [[ -d /usr/syno/etc/rc.sysv ]]; then
|
||||
CONF="/etc/init/${AGENT_NAME}.conf"
|
||||
log_info "Configuring Upstart service at $CONF..."
|
||||
|
||||
cat > "$CONF" <<EOF
|
||||
description "Pulse Unified Agent"
|
||||
author "Pulse"
|
||||
|
||||
start on syno.network.ready
|
||||
stop on runlevel [06]
|
||||
|
||||
respawn
|
||||
respawn limit 5 10
|
||||
|
||||
exec ${INSTALL_DIR}/${BINARY_NAME} \
|
||||
--url "${PULSE_URL}" \
|
||||
--token "${PULSE_TOKEN}" \
|
||||
--interval "${INTERVAL}" \
|
||||
--enable-host=${ENABLE_HOST} \
|
||||
--enable-docker=${ENABLE_DOCKER} \
|
||||
--insecure=${INSECURE} \
|
||||
>> ${LOG_FILE} 2>&1
|
||||
EOF
|
||||
initctl stop "${AGENT_NAME}" 2>/dev/null || true
|
||||
initctl start "${AGENT_NAME}"
|
||||
log_info "Service started."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 3. Linux (Systemd)
|
||||
if command -v systemctl >/dev/null 2>&1; then
|
||||
UNIT="/etc/systemd/system/${AGENT_NAME}.service"
|
||||
log_info "Configuring Systemd service at $UNIT..."
|
||||
|
||||
cat > "$UNIT" <<EOF
|
||||
[Unit]
|
||||
Description=Pulse Unified Agent
|
||||
After=network-online.target docker.service
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=${INSTALL_DIR}/${BINARY_NAME} \
|
||||
--url "${PULSE_URL}" \
|
||||
--token "${PULSE_TOKEN}" \
|
||||
--interval "${INTERVAL}" \
|
||||
--enable-host=${ENABLE_HOST} \
|
||||
--enable-docker=${ENABLE_DOCKER} \
|
||||
--insecure=${INSECURE}
|
||||
Restart=always
|
||||
RestartSec=5s
|
||||
User=root
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
systemctl daemon-reload
|
||||
systemctl enable "${AGENT_NAME}"
|
||||
systemctl restart "${AGENT_NAME}"
|
||||
log_info "Service started."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
fail "Could not detect a supported service manager (systemd, launchd, upstart)."
|
||||
@@ -106,6 +106,16 @@ common::fail() {
|
||||
done
|
||||
local message="${message_parts[*]}"
|
||||
common::log_error "${message}"
|
||||
|
||||
if common::is_interactive; then
|
||||
echo ""
|
||||
if [[ -t 0 ]]; then
|
||||
read -p "Press Enter to exit..."
|
||||
elif [[ -e /dev/tty ]]; then
|
||||
read -p "Press Enter to exit..." < /dev/tty
|
||||
fi
|
||||
fi
|
||||
|
||||
exit "${exit_code}"
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user