fix(agent): support PULSE_AGENT_CONNECT_URL and improve detection

This commit is contained in:
rcourtman 2025-12-19 17:01:58 +00:00
parent bede5162d3
commit 3b55639fbe
3 changed files with 24 additions and 15 deletions

View file

@ -100,7 +100,10 @@ Environment variables take precedence over `system.json`.
| `debug` | Verbose output including per-guest/storage polling details | | `debug` | Verbose output including per-guest/storage polling details |
> **Tip**: If your syslog is being flooded with Pulse messages, set `LOG_LEVEL=warn` to significantly reduce log volume while still capturing important events. > **Tip**: If your syslog is being flooded with Pulse messages, set `LOG_LEVEL=warn` to significantly reduce log volume while still capturing important events.
| `PULSE_PUBLIC_URL` | Public URL for notifications/OIDC | `""` |
| Variable | Description | Default |
|----------|-------------|---------|
| `PULSE_PUBLIC_URL` | URL for agent install commands, notifications, and OIDC. **Important for reverse proxy setups**: Set this to your internal Pulse URL (e.g., `http://192.168.1.10:7655`) so agents connect directly instead of through the proxy. | Auto-detected |
| `ALLOWED_ORIGINS` | CORS allowed domains | `""` (Same origin) | | `ALLOWED_ORIGINS` | CORS allowed domains | `""` (Same origin) |
| `DISCOVERY_ENABLED` | Auto-discover nodes | `false` | | `DISCOVERY_ENABLED` | Auto-discover nodes | `false` |
| `PULSE_ENABLE_SENSOR_PROXY` | Enable legacy `pulse-sensor-proxy` endpoints (deprecated, unsupported) | `false` | | `PULSE_ENABLE_SENSOR_PROXY` | Enable legacy `pulse-sensor-proxy` endpoints (deprecated, unsupported) | `false` |

View file

@ -14,7 +14,6 @@ import { getPulseBaseUrl } from '@/utils/url';
import { logger } from '@/utils/logger'; import { logger } from '@/utils/logger';
const TOKEN_PLACEHOLDER = '<api-token>'; const TOKEN_PLACEHOLDER = '<api-token>';
const pulseUrl = () => getPulseBaseUrl();
const buildDefaultTokenName = () => { const buildDefaultTokenName = () => {
const now = new Date(); const now = new Date();
@ -25,14 +24,16 @@ const buildDefaultTokenName = () => {
type AgentPlatform = 'linux' | 'macos' | 'windows'; type AgentPlatform = 'linux' | 'macos' | 'windows';
const commandsByPlatform: Record< // Generate platform-specific commands with the appropriate Pulse URL
// Uses agentUrl from API (PULSE_PUBLIC_URL) if configured, otherwise falls back to window.location
const buildCommandsByPlatform = (url: string): Record<
AgentPlatform, AgentPlatform,
{ {
title: string; title: string;
description: string; description: string;
snippets: { label: string; command: string; note?: string | any }[]; snippets: { label: string; command: string; note?: string | any }[];
} }
> = { > => ({
linux: { linux: {
title: 'Install on Linux', title: 'Install on Linux',
description: description:
@ -40,7 +41,7 @@ const commandsByPlatform: Record<
snippets: [ snippets: [
{ {
label: 'Install', label: 'Install',
command: `curl -fsSL ${pulseUrl()}/install.sh | sudo bash -s -- --url ${pulseUrl()} --token ${TOKEN_PLACEHOLDER} --interval 30s`, command: `curl -fsSL ${url}/install.sh | sudo bash -s -- --url ${url} --token ${TOKEN_PLACEHOLDER} --interval 30s`,
note: ( note: (
<span> <span>
Automatically detects your init system (systemd, OpenRC, Unraid, Synology) and configures the appropriate service. Works on Debian, Ubuntu, Fedora, Alpine, Gentoo, Unraid, Synology, and more. Automatically detects your init system (systemd, OpenRC, Unraid, Synology) and configures the appropriate service. Works on Debian, Ubuntu, Fedora, Alpine, Gentoo, Unraid, Synology, and more.
@ -56,7 +57,7 @@ const commandsByPlatform: Record<
snippets: [ snippets: [
{ {
label: 'Install with launchd', label: 'Install with launchd',
command: `curl -fsSL ${pulseUrl()}/install.sh | sudo bash -s -- --url ${pulseUrl()} --token ${TOKEN_PLACEHOLDER} --interval 30s`, command: `curl -fsSL ${url}/install.sh | sudo bash -s -- --url ${url} --token ${TOKEN_PLACEHOLDER} --interval 30s`,
note: ( note: (
<span> <span>
Creates <code>/Library/LaunchDaemons/com.pulse.agent.plist</code> and starts the agent automatically. Creates <code>/Library/LaunchDaemons/com.pulse.agent.plist</code> and starts the agent automatically.
@ -72,7 +73,7 @@ const commandsByPlatform: Record<
snippets: [ snippets: [
{ {
label: 'Install as Windows Service (PowerShell)', label: 'Install as Windows Service (PowerShell)',
command: `irm ${pulseUrl()}/install.ps1 | iex`, command: `irm ${url}/install.ps1 | iex`,
note: ( note: (
<span> <span>
Run in PowerShell as Administrator. The script will prompt for the Pulse URL and API token, download the agent binary, and install it as a Windows service with automatic startup. Run in PowerShell as Administrator. The script will prompt for the Pulse URL and API token, download the agent binary, and install it as a Windows service with automatic startup.
@ -81,7 +82,7 @@ const commandsByPlatform: Record<
}, },
{ {
label: 'Install with parameters (PowerShell)', label: 'Install with parameters (PowerShell)',
command: `$env:PULSE_URL="${pulseUrl()}"; $env:PULSE_TOKEN="${TOKEN_PLACEHOLDER}"; irm ${pulseUrl()}/install.ps1 | iex`, command: `$env:PULSE_URL="${url}"; $env:PULSE_TOKEN="${TOKEN_PLACEHOLDER}"; irm ${url}/install.ps1 | iex`,
note: ( note: (
<span> <span>
Non-interactive installation. Set environment variables before running to skip prompts. Non-interactive installation. Set environment variables before running to skip prompts.
@ -90,7 +91,7 @@ const commandsByPlatform: Record<
}, },
], ],
}, },
}; });
export const UnifiedAgents: Component = () => { export const UnifiedAgents: Component = () => {
const { state } = useWebSocket(); const { state } = useWebSocket();
@ -118,12 +119,16 @@ export const UnifiedAgents: Component = () => {
} }
}); });
const commandSections = createMemo(() => // Use agentUrl from API (PULSE_PUBLIC_URL) if configured, otherwise fall back to window.location
Object.entries(commandsByPlatform).map(([platform, meta]) => ({ const agentUrl = () => securityStatus()?.agentUrl || getPulseBaseUrl();
const commandSections = createMemo(() => {
const commands = buildCommandsByPlatform(agentUrl());
return Object.entries(commands).map(([platform, meta]) => ({
platform: platform as AgentPlatform, platform: platform as AgentPlatform,
...meta, ...meta,
})), }));
); });
const connectedFromStatus = (status: string | undefined | null) => { const connectedFromStatus = (status: string | undefined | null) => {
if (!status) return false; if (!status) return false;
@ -238,7 +243,7 @@ export const UnifiedAgents: Component = () => {
const getCurlInsecureFlag = () => insecureMode() ? '-k' : ''; const getCurlInsecureFlag = () => insecureMode() ? '-k' : '';
const getUninstallCommand = () => { const getUninstallCommand = () => {
return `curl ${getCurlInsecureFlag()}-fsSL ${pulseUrl()}/install.sh | sudo bash -s -- --uninstall`; return `curl ${getCurlInsecureFlag()}-fsSL ${agentUrl()}/install.sh | sudo bash -s -- --uninstall`;
}; };
// Track previously seen host types to prevent flapping when one source temporarily has no data // Track previously seen host types to prevent flapping when one source temporarily has no data
@ -370,7 +375,7 @@ export const UnifiedAgents: Component = () => {
const getUpgradeCommand = (_hostname: string) => { const getUpgradeCommand = (_hostname: string) => {
const token = resolvedToken(); const token = resolvedToken();
return `curl ${getCurlInsecureFlag()}-fsSL ${pulseUrl()}/install.sh | sudo bash -s -- --url ${pulseUrl()} --token ${token}${getInsecureFlag()}`; return `curl ${getCurlInsecureFlag()}-fsSL ${agentUrl()}/install.sh | sudo bash -s -- --url ${agentUrl()} --token ${token}${getInsecureFlag()}`;
}; };
const handleRemoveAgent = async (id: string, type: 'host' | 'docker' | 'kubernetes') => { const handleRemoveAgent = async (id: string, type: 'host' | 'docker' | 'kubernetes') => {

View file

@ -123,6 +123,7 @@ export interface SecurityStatus {
deprecatedDisableAuth?: boolean; deprecatedDisableAuth?: boolean;
message?: string; message?: string;
hideLocalLogin?: boolean; // Hide local login form hideLocalLogin?: boolean; // Hide local login form
agentUrl?: string; // URL for agent install commands (from PULSE_PUBLIC_URL or auto-detected)
} }
/** /**