The Settings page was telling systemd/bare metal users to run install.sh
for upgrades, which is wrong - install.sh is for fresh installations only
and does nothing if Pulse is already installed.
Changes:
- Updated upgrade instructions to mention built-in "Install Update" button
- Added correct manual upgrade steps (download tarball, stop service, extract, start)
- Removed misleading "run install.sh" instruction
This fixes a critical UX issue where users would run install.sh and think
nothing happened, when they should either:
1. Use the built-in automatic update feature (Install Update button)
2. Manually download and extract the new binary
Related files:
- frontend-modern/src/components/Settings/Settings.tsx:4052-4072
Modern Proxmox LXC containers (cgroup v2 + systemd) don't expose the CTID
inside the guest namespace. The auto-detection in DetectLXCCTID() works
for older LXC setups and when hostname is numeric, but fails for most
production containers where users set custom hostnames.
Changes:
- Added PULSE_LXC_CTID environment variable override in router.go:490-495
- Graceful fallback: auto-detect first, then check env var, then show placeholder
- UI already handles missing CTID by showing "pct exec <ctid>" placeholder
This provides a robust solution for thousands of users:
- Stock Proxmox LXC: Shows `pct exec <ctid>` placeholder (user substitutes manually)
- Custom hostname containers: Can set PULSE_LXC_CTID=171 in compose/systemd
- Numeric hostname containers: Auto-detected (backwards compatible)
Related: FirstRunSetup.tsx already has graceful fallback (line 336-339)
The "SSH Fallback" label was confusing to users. Changed to "Proxy (SSH)"
to make it clearer that the proxy is using SSH to collect temperature data
from cluster nodes.
This appears in the Capabilities column on Settings → Nodes when:
- Temperature monitoring is enabled
- Socket proxy is not available/healthy
- HTTPS proxy is not available/reachable
- Added DetectDockerContainerName() to detect container name from hostname
- Extended /api/security/status to expose dockerContainerName field
- Updated FirstRunSetup to show actual container name when detected:
* Before: 'docker exec <container-name> cat /data/.bootstrap_token'
* After: 'docker exec pulse cat /data/.bootstrap_token'
This reduces friction for users - no need to look up the container name.
Works when Docker container is named (--name flag), falls back to
placeholder for auto-generated container IDs.
- Added DetectLXCCTID() to internal/system/container.go to detect Proxmox container ID
- Extended /api/security/status to expose inContainer and lxcCtid fields
- Updated FirstRunSetup to show most relevant command based on detected environment:
* LXC with CTID: Shows 'pct exec 171 -- cat /etc/pulse/.bootstrap_token'
* Docker: Shows 'docker exec <container-name> cat /data/.bootstrap_token'
* Bare metal: Shows 'cat /etc/pulse/.bootstrap_token'
- Collapsed alternative methods behind 'Show other retrieval methods' button
This addresses user feedback that showing all options was overwhelming.
Now users see the command most likely to work for their setup first,
with alternatives hidden but still accessible.
The installer was adding node hostnames (and accidentally the header "Name")
to allowed_nodes in addition to IPs. This caused:
1. Invalid entries like "Name", "minipc", "delly" in config
2. These are not valid for SSH temperature collection
Only IPs should be in allowed_nodes since that's what the proxy uses for SSH.
Removed the loop that added CLUSTER_NODE_NAMES to the array.
Also fixed: Removed extraction of CLUSTER_NODE_NAMES since it's no longer used.
When Pulse runs in Docker inside a Proxmox LXC container, users need
specific instructions to retrieve the bootstrap token. Added pct exec
and pct enter commands to the Docker instructions section.
Now shows three scenarios:
1. Direct Docker host: docker exec
2. Kubernetes: kubectl exec
3. Proxmox LXC with Docker: pct exec / pct enter
This makes first-time setup easier for users deploying Pulse in LXC
containers on Proxmox.
Problem:
Cleanup script uses systemd-run with both --wait and
--property="After=pulse-sensor-cleanup.service", creating a circular
dependency:
- cleanup.service runs and waits for uninstaller to complete
- uninstaller has After=cleanup.service, so it waits for cleanup to finish
- Result: Both services stuck waiting for each other
Fix:
Remove the --property="After=pulse-sensor-cleanup.service" line. The
Conflicts=pulse-sensor-proxy.service is sufficient to ensure the proxy
stops before uninstallation. The cleanup script doesn't need to finish
before the uninstaller starts.
Testing:
Cleanup now completes successfully, removing all artifacts:
- Systemd units removed
- Binaries deleted from /opt/pulse/sensor-proxy/
- Data directory /var/lib/pulse-sensor-proxy/ removed
- SSH keys cleaned from authorized_keys
- pulse-monitor user and API tokens deleted
- LXC bind mounts removed from container configs
Related to #605 (temperature monitoring cleanup)
**Missed Migration**:
- Line 2204 still used /usr/local/bin/pulse-sensor-wrapper.sh in fallback path
- Updated to use /opt/pulse/sensor-proxy/bin/pulse-sensor-wrapper.sh
**Backward Compatibility**:
- When pushing SSH keys to cluster nodes, installer now checks if remote node
has old installation (/usr/local/bin wrapper exists but /opt path doesn't)
- Automatically creates symlink on remote nodes to maintain compatibility
- Prevents temperature collection failures when cluster has mixed old/new installs
**Root Cause**:
When installer runs on upgraded node (delly), it pushes SSH keys with new forced
command path to all cluster nodes. If remote node (minipc) has old installation,
the forced command fails because wrapper doesn't exist at new path.
This fix ensures "it works straight out the box" by bridging old and new paths
automatically during SSH key deployment.
Rewrote AWK state machine to correctly handle:
- Multiple allowed_nodes sections (removes all of them)
- Comment lines immediately preceding allowed_nodes (discards them)
- Empty lines within allowed_nodes section
- Indented list items and comments
The function now:
1. Buffers comment lines that might precede allowed_nodes
2. When allowed_nodes: is detected, discards buffered comments
3. Skips all content until hitting a non-indented, non-comment line
4. Flushes buffered comments when hitting non-comment content
This ensures running the installer multiple times won't create duplicate
allowed_nodes sections in config.yaml.
Tested with script that verifies duplicate sections are removed correctly.
Updated CLEANUP_TODO.md with comprehensive documentation of all 8 critical
issues identified by Codex review (conv-1763166192078-1076) and their
resolutions.
Key updates:
- Added detailed problem/fix/impact for each issue
- Updated status to 'Codex review complete, ready for deployment testing'
- Documented all commits in implementation history
- Added Codex review summary section
- Marked phases 1-6 as complete, phase 7 (testing) as pending
This provides complete audit trail of cleanup implementation work.