Merge pull request #2180 from rcourtman/maintainer/20260923T012852Z

Capture agent logs on FreeBSD/pfSense and fix the installer log hint
This commit is contained in:
pulse-triage[bot]
2026-09-23 02:09:40 +00:00
committed by GitHub
4 changed files with 107 additions and 6 deletions
@@ -1168,6 +1168,12 @@ update, profile rollout, command reachability, or fleet-control authority.
`shasum`, so checksum verification must fall back through the digest tools
actually present on the target platform rather than failing a valid agent
download when coreutils is absent.
FreeBSD-family diagnostics are part of that lifecycle too. The rc.d service
has no journal and `daemon(8)` does not capture the child's stdout, so the
rendered service must pass an installer-owned rotating `--log-file` and the
installer's completion hint must name that file. A platform system log is
not a substitute: pfSense ships no `/var/log/messages`, and repointing the
hint at a log that receives no agent output would still strand the operator.
Server update planning is part of the same lifecycle contract. The System
Updates plan must surface a structured upgrade-readiness verdict before an
@@ -1078,8 +1078,13 @@ artifact-selection behaviour.
platform. FreeBSD base ships `sha256(1)` and neither GNU `sha256sum` nor
Perl `shasum`, so the unified installer and the MCP installer must fall back
through the available digest tool instead of refusing an otherwise correct
download. The shared installer helper owns that fallback so every download
(agent, typed helper, action runner) is verified consistently.
download. The shared installer helper owns that fallback so every download
(agent, typed helper, action runner) is verified consistently.
FreeBSD and pfSense installs must likewise leave the agent with a durable,
installer-owned rotating log. rc.d has no journal and `daemon(8)` discards
the child's stdout, so the rendered rc.d service must carry the agent's
`--log-file` and the install summary must point at that file rather than
`/var/log/messages`, which pfSense does not ship.
The shell installer must disclose `--enable-commands` as Pulse command
execution, disabled by default, and must name both Patrol actions and
Proxmox LXC Docker inventory as the operator-visible reasons to enable it.
+16 -3
View File
@@ -6821,6 +6821,13 @@ if [[ "$TRUENAS" == true ]]; then
mkdir -p "$TRUENAS_STATE_DIR"
mkdir -p "$TRUENAS_LOG_DIR"
# FreeBSD rc.d has no journal and daemon(8) does not capture the child's
# stdout, so the agent's own rotating writer must own its log. On Linux the
# systemd unit captures stdout via journald instead.
if [[ "$(uname -s)" == "FreeBSD" ]]; then
AGENT_LOG_FILE="${TRUENAS_LOG_DIR}/${AGENT_NAME}.log"
fi
TRUENAS_STORED_BINARY="$TRUENAS_STATE_DIR/${BINARY_NAME}"
# Move binary to persistent storage location
@@ -6958,7 +6965,7 @@ EOF
log_info "Logs: tail -f ${TRUENAS_LOG_FILE}"
elif [[ "$(uname -s)" == "FreeBSD" ]]; then
log_info "Service: $TRUENAS_SERVICE_STORAGE (symlinked to rc.d)"
log_info "Logs: tail -f /var/log/messages"
log_info "Logs: tail -f ${AGENT_LOG_FILE}"
fi
log_info ""
log_info "The Init/Shutdown task ensures the agent survives TrueNAS upgrades."
@@ -7023,6 +7030,12 @@ if [[ "$OS" == "freebsd" ]] || [[ -f /etc/rc.subr ]]; then
RCSCRIPT="/usr/local/etc/rc.d/${AGENT_NAME}"
log_info "Configuring FreeBSD rc.d service at $RCSCRIPT..."
# FreeBSD rc.d has no journal, and daemon(8) does not capture the child's
# stdout, so the agent's own rotating writer must own its log. Without this
# the agent logs are lost and the completion hint below would point at a
# system log that never receives them (and that pfSense does not even ship).
AGENT_LOG_FILE="${STATE_DIR}/logs/${AGENT_NAME}.log"
# Build command line args
ensure_runtime_token_file "$STATE_DIR"
clear_proxmox_state_if_needed
@@ -7050,9 +7063,9 @@ BOOTEOF
# Stop existing agent if running
restart_sysv_agent_service "$RCSCRIPT"
complete_installation_flow "$STATE_DIR" "Installation complete! Agent is running." "Upgrade complete! Agent restarted with new configuration." "tail -f /var/log/messages"
complete_installation_flow "$STATE_DIR" "Installation complete! Agent is running." "Upgrade complete! Agent restarted with new configuration." "tail -f ${AGENT_LOG_FILE}"
log_info "To check status: $RCSCRIPT status"
log_info "To view logs: tail -f /var/log/messages"
log_info "To view logs: tail -f ${AGENT_LOG_FILE}"
exit 0
fi
+78 -1
View File
@@ -2658,6 +2658,83 @@ func TestInstallSHFreeBSDRendererUsesDaemonSupervisorPidfile(t *testing.T) {
}
}
// TestInstallSHFreeBSDAgentLogsUseRotatingWriter pins the FreeBSD half of the
// log-capture fix for issue #2123: rc.d has no journal and daemon(8) does not
// capture the child's stdout, so the agent must own a rotating --log-file and
// the completion hint must point at it. pfSense has no /var/log/messages, so
// the old system-log hint is removed entirely rather than repointed.
func TestInstallSHFreeBSDAgentLogsUseRotatingWriter(t *testing.T) {
content, err := os.ReadFile(repoFile("scripts", "install.sh"))
if err != nil {
t.Fatalf("read install.sh: %v", err)
}
script := string(content)
required := []string{
`AGENT_LOG_FILE="${STATE_DIR}/logs/${AGENT_NAME}.log"`,
`AGENT_LOG_FILE="${TRUENAS_LOG_DIR}/${AGENT_NAME}.log"`,
`complete_installation_flow "$STATE_DIR" "Installation complete! Agent is running." "Upgrade complete! Agent restarted with new configuration." "tail -f ${AGENT_LOG_FILE}"`,
`log_info "To view logs: tail -f ${AGENT_LOG_FILE}"`,
}
for _, needle := range required {
if !strings.Contains(script, needle) {
t.Fatalf("install.sh missing FreeBSD rotating agent log wiring: %s", needle)
}
}
if strings.Contains(script, "tail -f /var/log/messages") {
t.Fatal("install.sh still points FreeBSD/pfSense users at /var/log/messages, which does not exist on pfSense")
}
}
// TestInstallSHFreeBSDBuildArgsPassesLogFile verifies the FreeBSD rc.d service
// args actually carry --log-file once AGENT_LOG_FILE is set.
func TestInstallSHFreeBSDBuildArgsPassesLogFile(t *testing.T) {
script := `
PULSE_URL="http://pulse.local:7655"
PULSE_TOKEN=""
INTERVAL="30s"
INTERVAL_EXPLICIT="false"
ENABLE_HOST="true"
HOST_EXPLICIT="false"
ENABLE_DOCKER=""
DOCKER_EXPLICIT="false"
ENABLE_KUBERNETES=""
KUBERNETES_EXPLICIT="false"
KUBECONFIG_PATH=""
ENABLE_PROXMOX=""
PROXMOX_EXPLICIT="false"
PROXMOX_TYPE=""
INSECURE="false"
ENABLE_COMMANDS="false"
ENROLL="false"
HEALTH_ADDR=""
HEALTH_ADDR_SET="false"
AGENT_ID=""
HOSTNAME_OVERRIDE=""
STATE_DIR="/var/lib/pulse-agent"
CURL_CA_BUNDLE=""
KUBE_INCLUDE_ALL_PODS="false"
KUBE_INCLUDE_ALL_DEPLOYMENTS="false"
DISK_EXCLUDES=()
DISK_INCLUDES=()
RUNTIME_TOKEN_FILE=""
AGENT_LOG_FILE="/var/lib/pulse-agent/logs/pulse-agent.log"
` + extractInstallShellFunction(t, "build_exec_arg_items") + `
` + extractInstallShellFunction(t, "join_exec_arg_items") + `
` + extractInstallShellFunction(t, "build_exec_args") + `
build_exec_args
printf 'EXEC_ARGS=%s\n' "$EXEC_ARGS"
`
out, err := exec.Command("bash", "-c", script).CombinedOutput()
if err != nil {
t.Fatalf("bash: %v\n%s", err, out)
}
got := string(out)
if !strings.Contains(got, "--log-file /var/lib/pulse-agent/logs/pulse-agent.log") {
t.Fatalf("FreeBSD service args missing rotating --log-file:\n%s", got)
}
}
func TestInstallSHUsesCanonicalCompletionHelper(t *testing.T) {
content, err := os.ReadFile(repoFile("scripts", "install.sh"))
if err != nil {
@@ -2676,7 +2753,7 @@ func TestInstallSHUsesCanonicalCompletionHelper(t *testing.T) {
`complete_installation_flow "$UNRAID_STORAGE_DIR" "Installation complete! Agent is running." "Upgrade complete! Agent is running." "tail -f ${AGENT_LOG_FILE}"`,
`complete_installation_flow "$STATE_DIR" "Installation complete! Agent is running." "Upgrade complete! Agent is running." "tail -f ${AGENT_LOG_FILE}"`,
`complete_installation_flow "$TRUENAS_STATE_DIR" "Installation complete! Agent is running." "Upgrade complete! Agent is running." ""`,
`complete_installation_flow "$STATE_DIR" "Installation complete! Agent is running." "Upgrade complete! Agent restarted with new configuration." "tail -f /var/log/messages"`,
`complete_installation_flow "$STATE_DIR" "Installation complete! Agent is running." "Upgrade complete! Agent restarted with new configuration." "tail -f ${AGENT_LOG_FILE}"`,
`complete_installation_flow "$STATE_DIR" "Installation complete! Agent is running." "Upgrade complete! Agent restarted with new configuration." "journalctl -u ${AGENT_NAME} --no-pager -n 20"`,
`complete_installation_flow "$STATE_DIR" "Installation complete! Agent is running." "Upgrade complete! Agent restarted with new configuration." "tail -f /var/log/${AGENT_NAME}.log"`,
}