fix: show Removed Docker Hosts section in UI for re-enrollment

The 'Removed Docker Hosts' section was not appearing in Settings -> Agents
even when hosts were blocked from re-enrolling. This prevented users from
using the 'Allow re-enroll' button to unblock their Docker agents.

Root cause: The WebSocket store was missing:
1. The 'removedDockerHosts' property in its initial state
2. A handler to process removedDockerHosts data from WebSocket messages

This meant the backend was correctly sending the data, but the frontend
was completely ignoring it.

Changes:
- Add removedDockerHosts to WebSocket store initial state and message handler
- Add removedDockerHosts to App.tsx fallback state for consistency
- Add missing BroadcastState call after AllowDockerHostReenroll succeeds

Also includes previous fixes from this session:
- Add PULSE_AGENT_URL as alias for PULSE_AGENT_CONNECT_URL (config.go)
- Add runtime Docker/Podman auto-detection in pulse-agent (main.go)

Fixes issue reported by darthrater78 in discussion #845
This commit is contained in:
rcourtman 2025-12-19 17:57:04 +00:00
parent b4db8b160b
commit 97c851c16c
5 changed files with 47 additions and 0 deletions

View file

@ -6,6 +6,7 @@ import (
"fmt"
"net/http"
"os"
"os/exec"
"os/signal"
"strconv"
"strings"
@ -146,6 +147,20 @@ func main() {
})
}
// Auto-detect Docker/Podman if not explicitly configured
if !cfg.EnableDocker && !cfg.DockerConfigured {
// Check for docker binary
if _, err := exec.LookPath("docker"); err == nil {
logger.Info().Msg("Auto-detected Docker binary, enabling Docker monitoring")
cfg.EnableDocker = true
} else if _, err := exec.LookPath("podman"); err == nil {
logger.Info().Msg("Auto-detected Podman binary, enabling Docker monitoring")
cfg.EnableDocker = true
} else {
logger.Debug().Msg("Docker/Podman not found, skipping Docker monitoring")
}
}
// 9. Start Docker Agent (if enabled)
var dockerAgent *dockeragent.Agent
if cfg.EnableDocker {
@ -324,6 +339,7 @@ type Config struct {
// Module flags
EnableHost bool
EnableDocker bool
DockerConfigured bool
EnableKubernetes bool
EnableProxmox bool
ProxmoxType string // "pve", "pbs", or "" for auto-detect
@ -460,6 +476,16 @@ func loadConfig() Config {
kubeIncludeNamespaces := gatherCSV(envKubeIncludeNamespaces, kubeIncludeNamespaceFlags)
kubeExcludeNamespaces := gatherCSV(envKubeExcludeNamespaces, kubeExcludeNamespaceFlags)
// Check if Docker was explicitly configured via flag or env
dockerConfigured := envEnableDocker != ""
if !dockerConfigured {
flag.Visit(func(f *flag.Flag) {
if f.Name == "enable-docker" {
dockerConfigured = true
}
})
}
return Config{
PulseURL: pulseURL,
APIToken: token,
@ -471,6 +497,7 @@ func loadConfig() Config {
LogLevel: logLevel,
EnableHost: *enableHostFlag,
EnableDocker: *enableDockerFlag,
DockerConfigured: dockerConfigured,
EnableKubernetes: *enableKubernetesFlag,
EnableProxmox: *enableProxmoxFlag,
ProxmoxType: strings.TrimSpace(*proxmoxTypeFlag),

View file

@ -268,6 +268,7 @@ function App() {
vms: [],
containers: [],
dockerHosts: [],
removedDockerHosts: [],
hosts: [],
storage: [],
cephClusters: [],

View file

@ -11,6 +11,7 @@ import type {
DockerHost,
Host,
KubernetesCluster,
RemovedDockerHost,
RemovedKubernetesCluster,
} from '@/types/api';
import type { ActivationState as ActivationStateType } from '@/types/alerts';
@ -32,6 +33,7 @@ export function createWebSocketStore(url: string) {
vms: [],
containers: [],
dockerHosts: [],
removedDockerHosts: [],
kubernetesClusters: [],
removedKubernetesClusters: [],
hosts: [],
@ -579,6 +581,12 @@ export function createWebSocketStore(url: string) {
setState('hosts', reconcile(processedHosts, { key: 'id' }));
}
}
if (message.data.removedDockerHosts !== undefined) {
const removed = Array.isArray(message.data.removedDockerHosts)
? (message.data.removedDockerHosts as RemovedDockerHost[])
: [];
setState('removedDockerHosts', reconcile(removed, { key: 'id' }));
}
if (message.data.kubernetesClusters !== undefined) {
const clusters = Array.isArray(message.data.kubernetesClusters)
? (message.data.kubernetesClusters as KubernetesCluster[])

View file

@ -338,6 +338,9 @@ func (h *DockerAgentHandlers) HandleAllowReenroll(w http.ResponseWriter, r *http
return
}
// Broadcast updated state to ensure the frontend reflects the change
go h.wsHub.BroadcastState(h.monitor.GetState().ToFrontend())
if err := utils.WriteJSONResponse(w, map[string]any{
"success": true,
"hostId": hostID,

View file

@ -1230,6 +1230,14 @@ func Load() (*Config, error) {
log.Debug().Str("key_file", tlsKeyFile).Msg("TLS key file from env var")
}
// Support PULSE_AGENT_URL as an alias for PULSE_AGENT_CONNECT_URL
// (Check this first so standard PULSE_AGENT_CONNECT_URL takes precedence if both set)
if agentURL := utils.GetenvTrim("PULSE_AGENT_URL"); agentURL != "" {
cfg.AgentConnectURL = agentURL
cfg.EnvOverrides["PULSE_AGENT_CONNECT_URL"] = true
log.Info().Str("url", agentURL).Msg("Using dedicated agent connect URL from PULSE_AGENT_URL")
}
if agentConnectURL := utils.GetenvTrim("PULSE_AGENT_CONNECT_URL"); agentConnectURL != "" {
cfg.AgentConnectURL = agentConnectURL
cfg.EnvOverrides["PULSE_AGENT_CONNECT_URL"] = true