mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-22 11:13:26 +00:00
feat: add toggle to disable network discovery
Addresses #343 - users can now disable Proxmox/PBS server discovery through: - UI toggle in Settings > System > Network Settings - Environment variable DISCOVERY_ENABLED=false - system.json configuration Discovery runs by default but can be completely disabled for environments where automatic scanning causes issues (e.g., shared hosting networks).
This commit is contained in:
@@ -67,7 +67,9 @@ ENABLE_AUDIT_LOG=true # Enable security audit logging
|
||||
"autoUpdateTime": "03:00", // Time for automatic updates (24hr format)
|
||||
"allowedOrigins": "", // CORS allowed origins (empty = same-origin only)
|
||||
"backendPort": 7655, // Backend API port
|
||||
"frontendPort": 7655 // Frontend UI port (same as backend in embedded mode)
|
||||
"frontendPort": 7655, // Frontend UI port (same as backend in embedded mode)
|
||||
"discoveryEnabled": true, // Enable/disable network discovery for Proxmox/PBS servers
|
||||
"discoverySubnet": "auto" // Subnet to scan ("auto" or CIDR like "192.168.1.0/24")
|
||||
}
|
||||
```
|
||||
|
||||
@@ -130,6 +132,7 @@ Settings are loaded in this order (later overrides earlier):
|
||||
#### Configuration Variables (override system.json)
|
||||
These env vars override system.json values. When set, the UI will show a warning and disable the affected fields:
|
||||
|
||||
- `DISCOVERY_ENABLED` - Enable/disable network discovery (default: true)
|
||||
- `DISCOVERY_SUBNET` - Custom network to scan (default: auto-scans common networks)
|
||||
- `CONNECTION_TIMEOUT` - API timeout in seconds (default: 10)
|
||||
- `ALLOWED_ORIGINS` - CORS origins (default: same-origin only)
|
||||
|
||||
@@ -17,6 +17,10 @@ bash -c "$(wget -qLO - https://github.com/community-scripts/ProxmoxVE/raw/main/c
|
||||
**Auto-discovery (Easiest)**: Settings → Nodes → Click "Setup Script" on discovered node → Run on Proxmox
|
||||
**Manual**: Settings → Nodes → Add Node → Enter credentials → Save
|
||||
|
||||
### How do I disable network discovery?
|
||||
Settings → System → Network Settings → Toggle "Enable Discovery" off → Save
|
||||
Or set environment variable `DISCOVERY_ENABLED=false`
|
||||
|
||||
### How do I change the port?
|
||||
Systemd: `sudo systemctl edit pulse-backend`, add `Environment="FRONTEND_PORT=8080"`, restart
|
||||
Docker: Use `-e FRONTEND_PORT=8080` in your run command
|
||||
|
||||
@@ -98,6 +98,8 @@ const Settings: Component = () => {
|
||||
// System settings
|
||||
// PBS polling interval removed - fixed at 10 seconds
|
||||
const [allowedOrigins, setAllowedOrigins] = createSignal('*');
|
||||
const [discoveryEnabled, setDiscoveryEnabled] = createSignal(true);
|
||||
const [discoverySubnet, setDiscoverySubnet] = createSignal('auto');
|
||||
const [envOverrides, setEnvOverrides] = createSignal<Record<string, boolean>>({});
|
||||
// Connection timeout removed - backend-only setting
|
||||
|
||||
@@ -354,6 +356,9 @@ const Settings: Component = () => {
|
||||
// PBS polling interval is now fixed at 10 seconds
|
||||
setAllowedOrigins(systemSettings.allowedOrigins || '*');
|
||||
// Connection timeout is backend-only
|
||||
// Load discovery settings
|
||||
setDiscoveryEnabled(systemSettings.discoveryEnabled !== false); // Default to true
|
||||
setDiscoverySubnet(systemSettings.discoverySubnet || 'auto');
|
||||
// Load auto-update settings
|
||||
setAutoUpdateEnabled(systemSettings.autoUpdateEnabled || false);
|
||||
setAutoUpdateCheckInterval(systemSettings.autoUpdateCheckInterval || 24);
|
||||
@@ -396,6 +401,8 @@ const Settings: Component = () => {
|
||||
// PBS polling interval is now fixed at 10 seconds
|
||||
allowedOrigins: allowedOrigins(),
|
||||
// Connection timeout is backend-only
|
||||
discoveryEnabled: discoveryEnabled(),
|
||||
discoverySubnet: discoverySubnet(),
|
||||
updateChannel: updateChannel(),
|
||||
autoUpdateEnabled: autoUpdateEnabled(),
|
||||
autoUpdateCheckInterval: autoUpdateCheckInterval(),
|
||||
@@ -1202,6 +1209,78 @@ const Settings: Component = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Discovery Settings */}
|
||||
<div class="mt-4 pt-4 border-t border-gray-200 dark:border-gray-600">
|
||||
<label class="text-sm font-medium text-gray-900 dark:text-gray-100">Network Discovery</label>
|
||||
<p class="text-xs text-gray-600 dark:text-gray-400 mb-2">Automatically scan for Proxmox/PBS servers on your network</p>
|
||||
|
||||
{/* Discovery Toggle */}
|
||||
<div class="flex items-center justify-between mb-3">
|
||||
<span class="text-sm text-gray-700 dark:text-gray-300">Enable Discovery</span>
|
||||
<label class="relative inline-flex items-center cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={discoveryEnabled()}
|
||||
onChange={(e) => {
|
||||
if (!envOverrides().discoveryEnabled) {
|
||||
setDiscoveryEnabled(e.currentTarget.checked);
|
||||
setHasUnsavedChanges(true);
|
||||
}
|
||||
}}
|
||||
disabled={envOverrides().discoveryEnabled}
|
||||
class="sr-only peer"
|
||||
/>
|
||||
<div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 dark:peer-focus:ring-blue-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600 peer-disabled:opacity-50 peer-disabled:cursor-not-allowed"></div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{/* Discovery Subnet */}
|
||||
<Show when={discoveryEnabled()}>
|
||||
<div>
|
||||
<label class="text-sm text-gray-700 dark:text-gray-300">Discovery Subnet</label>
|
||||
<p class="text-xs text-gray-600 dark:text-gray-400 mb-1">Use "auto" for automatic detection or specify CIDR (e.g., 192.168.1.0/24)</p>
|
||||
<input
|
||||
type="text"
|
||||
value={discoverySubnet()}
|
||||
onChange={(e) => {
|
||||
if (!envOverrides().discoverySubnet) {
|
||||
setDiscoverySubnet(e.currentTarget.value);
|
||||
setHasUnsavedChanges(true);
|
||||
}
|
||||
}}
|
||||
disabled={envOverrides().discoverySubnet}
|
||||
placeholder="auto"
|
||||
class={`w-full px-3 py-1.5 text-sm border rounded-lg ${
|
||||
envOverrides().discoverySubnet
|
||||
? 'border-amber-300 dark:border-amber-600 bg-amber-50 dark:bg-amber-900/20 cursor-not-allowed opacity-75'
|
||||
: 'border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800'
|
||||
}`}
|
||||
/>
|
||||
{envOverrides().discoverySubnet && (
|
||||
<div class="mt-2 p-2 bg-amber-100 dark:bg-amber-900/30 border border-amber-300 dark:border-amber-700 rounded text-xs text-amber-800 dark:text-amber-200">
|
||||
<div class="flex items-center gap-1">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
|
||||
</svg>
|
||||
<span>Overridden by DISCOVERY_SUBNET environment variable</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Show>
|
||||
|
||||
{envOverrides().discoveryEnabled && (
|
||||
<div class="mt-2 p-2 bg-amber-100 dark:bg-amber-900/30 border border-amber-300 dark:border-amber-700 rounded text-xs text-amber-800 dark:text-amber-200">
|
||||
<div class="flex items-center gap-1">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
|
||||
</svg>
|
||||
<span>Overridden by DISCOVERY_ENABLED environment variable</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div class="mt-3 p-3 bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800 rounded-lg">
|
||||
<p class="text-xs text-amber-800 dark:text-amber-200 mb-2">
|
||||
<strong>Port Configuration:</strong> Edit <code class="font-mono bg-amber-100 dark:bg-amber-800 px-1 rounded">/etc/pulse/.env</code>
|
||||
|
||||
@@ -37,6 +37,8 @@ export interface SystemConfig {
|
||||
backendPort?: number; // Backend API port (default: 7655)
|
||||
frontendPort?: number; // Frontend UI port (default: 7655)
|
||||
theme?: string; // Theme preference: 'light' | 'dark' | undefined (system default)
|
||||
discoveryEnabled?: boolean; // Enable/disable network discovery
|
||||
discoverySubnet?: string; // Subnet to scan for discovery (default: 'auto')
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -108,6 +108,12 @@ func (h *SystemSettingsHandler) HandleUpdateSystemSettings(w http.ResponseWriter
|
||||
http.Error(w, "Invalid theme value. Must be 'light', 'dark', or empty", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Update discovery settings
|
||||
h.config.DiscoveryEnabled = settings.DiscoveryEnabled
|
||||
if settings.DiscoverySubnet != "" {
|
||||
h.config.DiscoverySubnet = settings.DiscoverySubnet
|
||||
}
|
||||
|
||||
// Save to persistence
|
||||
if err := h.persistence.SaveSystemSettings(settings); err != nil {
|
||||
|
||||
@@ -102,7 +102,8 @@ type Config struct {
|
||||
AutoUpdateTime string `envconfig:"AUTO_UPDATE_TIME" default:"03:00"`
|
||||
|
||||
// Discovery settings
|
||||
DiscoverySubnet string `envconfig:"DISCOVERY_SUBNET" default:"auto"`
|
||||
DiscoveryEnabled bool `envconfig:"DISCOVERY_ENABLED" default:"true"`
|
||||
DiscoverySubnet string `envconfig:"DISCOVERY_SUBNET" default:"auto"`
|
||||
|
||||
// Deprecated - for backward compatibility
|
||||
Port int `envconfig:"PORT"` // Maps to BackendPort
|
||||
@@ -209,6 +210,7 @@ func Load() (*Config, error) {
|
||||
PollingInterval: 10 * time.Second, // Deprecated - not used
|
||||
PVEPollingInterval: 10 * time.Second, // Deprecated - not used
|
||||
PBSPollingInterval: 60 * time.Second, // Default PBS polling (slower)
|
||||
DiscoveryEnabled: true,
|
||||
DiscoverySubnet: "auto",
|
||||
EnvOverrides: make(map[string]bool),
|
||||
}
|
||||
@@ -271,6 +273,8 @@ func Load() (*Config, error) {
|
||||
if systemSettings.LogLevel != "" {
|
||||
cfg.LogLevel = systemSettings.LogLevel
|
||||
}
|
||||
// Always load DiscoveryEnabled even if false
|
||||
cfg.DiscoveryEnabled = systemSettings.DiscoveryEnabled
|
||||
if systemSettings.DiscoverySubnet != "" {
|
||||
cfg.DiscoverySubnet = systemSettings.DiscoverySubnet
|
||||
}
|
||||
@@ -409,6 +413,11 @@ func Load() (*Config, error) {
|
||||
}
|
||||
// Support env vars for important settings (override system.json)
|
||||
// NOTE: Environment variables always take precedence over UI/system.json settings
|
||||
if discoveryEnabled := os.Getenv("DISCOVERY_ENABLED"); discoveryEnabled != "" {
|
||||
cfg.DiscoveryEnabled = discoveryEnabled == "true" || discoveryEnabled == "1"
|
||||
cfg.EnvOverrides["discoveryEnabled"] = true
|
||||
log.Info().Bool("enabled", cfg.DiscoveryEnabled).Msg("Discovery enabled overridden by DISCOVERY_ENABLED env var")
|
||||
}
|
||||
if discoverySubnet := os.Getenv("DISCOVERY_SUBNET"); discoverySubnet != "" {
|
||||
cfg.DiscoverySubnet = discoverySubnet
|
||||
cfg.EnvOverrides["discoverySubnet"] = true
|
||||
@@ -477,6 +486,7 @@ func SaveConfig(cfg *Config) error {
|
||||
AllowedOrigins: cfg.AllowedOrigins,
|
||||
ConnectionTimeout: int(cfg.ConnectionTimeout.Seconds()),
|
||||
LogLevel: cfg.LogLevel,
|
||||
DiscoveryEnabled: cfg.DiscoveryEnabled,
|
||||
DiscoverySubnet: cfg.DiscoverySubnet,
|
||||
// APIToken removed - now handled via .env only
|
||||
}
|
||||
|
||||
@@ -313,6 +313,7 @@ type SystemSettings struct {
|
||||
AutoUpdateCheckInterval int `json:"autoUpdateCheckInterval,omitempty"`
|
||||
AutoUpdateTime string `json:"autoUpdateTime,omitempty"`
|
||||
LogLevel string `json:"logLevel,omitempty"`
|
||||
DiscoveryEnabled bool `json:"discoveryEnabled"`
|
||||
DiscoverySubnet string `json:"discoverySubnet,omitempty"`
|
||||
Theme string `json:"theme,omitempty"` // User theme preference: "light", "dark", or empty for system default
|
||||
// APIToken removed - now handled via .env file only
|
||||
|
||||
@@ -294,17 +294,22 @@ func (m *Monitor) Start(ctx context.Context, wsHub *websocket.Hub) {
|
||||
Dur("pollingInterval", 10*time.Second).
|
||||
Msg("Starting monitoring loop")
|
||||
|
||||
// Initialize and start discovery service
|
||||
discoverySubnet := m.config.DiscoverySubnet
|
||||
if discoverySubnet == "" {
|
||||
discoverySubnet = "auto"
|
||||
}
|
||||
m.discoveryService = discovery.NewService(wsHub, 5*time.Minute, discoverySubnet)
|
||||
if m.discoveryService != nil {
|
||||
m.discoveryService.Start(ctx)
|
||||
log.Info().Msg("Discovery service initialized and started")
|
||||
// Initialize and start discovery service if enabled
|
||||
if m.config.DiscoveryEnabled {
|
||||
discoverySubnet := m.config.DiscoverySubnet
|
||||
if discoverySubnet == "" {
|
||||
discoverySubnet = "auto"
|
||||
}
|
||||
m.discoveryService = discovery.NewService(wsHub, 5*time.Minute, discoverySubnet)
|
||||
if m.discoveryService != nil {
|
||||
m.discoveryService.Start(ctx)
|
||||
log.Info().Msg("Discovery service initialized and started")
|
||||
} else {
|
||||
log.Error().Msg("Failed to initialize discovery service")
|
||||
}
|
||||
} else {
|
||||
log.Error().Msg("Failed to initialize discovery service")
|
||||
log.Info().Msg("Discovery service disabled by configuration")
|
||||
m.discoveryService = nil
|
||||
}
|
||||
|
||||
// Set up alert callbacks
|
||||
|
||||
Reference in New Issue
Block a user