mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-02 20:29:43 +00:00
Integrate reviewed command-channel troubleshooting guidance
Preserve the exact product-intelligence candidate and clarify execution scope versus live channel admission without changing runtime behaviour. Change-source: pulse-maintainer
This commit is contained in:
commit
fc4deb6c17
3 changed files with 124 additions and 1 deletions
|
|
@ -1000,6 +1000,11 @@ LXC guests** in Settings → System → General and any configured
|
|||
guests and guests already linked to an online guest-local agent. In the latter
|
||||
case, check that guest agent's Docker monitoring instead.
|
||||
|
||||
If the owning node says **Remote control blocked**, first check its
|
||||
[command channel](#commands-enabled-but-remote-control-blocked). A successful
|
||||
root `pct exec` check does not establish that Pulse can reach that node's agent;
|
||||
do not repeat the guest probe when those results are already known.
|
||||
|
||||
The host-side path requires the guest's `docker` executable and
|
||||
`/var/run/docker.sock` in the root `pct exec` context. A working Docker CLI in a
|
||||
user's login session does not prove that this context can reach the daemon;
|
||||
|
|
@ -1036,6 +1041,38 @@ Review output before posting and redact any private endpoint in an error. Do not
|
|||
change LXC privilege, `keyctl`, socket permissions or Docker versions merely to
|
||||
test a guess.
|
||||
|
||||
### Commands enabled but remote control blocked
|
||||
|
||||
**Remote control blocked** means the agent reports commands enabled, but Pulse
|
||||
has no admitted command channel connected for it. Agent Doctor's
|
||||
`commands command-capable · credential grants exec` line describes the reported
|
||||
local command ceiling and credential scope, not a connected session. A fresh
|
||||
monitoring report or **Automatic updates ready** also does not prove that this
|
||||
separate WebSocket channel is working. Changing Proxmox API permissions cannot
|
||||
repair a Pulse command-channel connection.
|
||||
|
||||
For a systemd agent, inspect the recent journal **locally on the affected node**:
|
||||
|
||||
```bash
|
||||
sudo journalctl -u pulse-agent.service --since '15 minutes ago' -n 200 --no-pager --output=cat
|
||||
```
|
||||
|
||||
Look for **Connected and registered with Pulse command server**, or
|
||||
**WebSocket connection failed repeatedly, reconnecting** and its error. A
|
||||
`dial websocket` error is a connection/handshake failure; `registration failed`
|
||||
means registration was attempted but not accepted. Scope alone does not prove
|
||||
that the credential's host/agent binding was admitted. No matching entry is
|
||||
inconclusive: initial retries may be debug-only; do not restart the host or
|
||||
enable server-wide debug logging to manufacture an error.
|
||||
|
||||
If reporting the problem, share only the failure stage and redacted error
|
||||
reason (or say no command-channel entry is visible), not the full journal or
|
||||
service configuration. Omit tokens, cookies, URLs, hostnames, addresses and
|
||||
agent/token IDs. Keep saved identity and credentials intact while distinguishing
|
||||
connection failures from admission failures; do not delete state, loosen TLS
|
||||
verification or broaden permissions to force a connection. Guest-local Docker
|
||||
monitoring with commands disabled remains an alternative to host-side discovery.
|
||||
|
||||
### Check Status
|
||||
```bash
|
||||
# Linux
|
||||
|
|
|
|||
|
|
@ -1000,6 +1000,11 @@ LXC guests** in Settings → System → General and any configured
|
|||
guests and guests already linked to an online guest-local agent. In the latter
|
||||
case, check that guest agent's Docker monitoring instead.
|
||||
|
||||
If the owning node says **Remote control blocked**, first check its
|
||||
[command channel](#commands-enabled-but-remote-control-blocked). A successful
|
||||
root `pct exec` check does not establish that Pulse can reach that node's agent;
|
||||
do not repeat the guest probe when those results are already known.
|
||||
|
||||
The host-side path requires the guest's `docker` executable and
|
||||
`/var/run/docker.sock` in the root `pct exec` context. A working Docker CLI in a
|
||||
user's login session does not prove that this context can reach the daemon;
|
||||
|
|
@ -1036,6 +1041,38 @@ Review output before posting and redact any private endpoint in an error. Do not
|
|||
change LXC privilege, `keyctl`, socket permissions or Docker versions merely to
|
||||
test a guess.
|
||||
|
||||
### Commands enabled but remote control blocked
|
||||
|
||||
**Remote control blocked** means the agent reports commands enabled, but Pulse
|
||||
has no admitted command channel connected for it. Agent Doctor's
|
||||
`commands command-capable · credential grants exec` line describes the reported
|
||||
local command ceiling and credential scope, not a connected session. A fresh
|
||||
monitoring report or **Automatic updates ready** also does not prove that this
|
||||
separate WebSocket channel is working. Changing Proxmox API permissions cannot
|
||||
repair a Pulse command-channel connection.
|
||||
|
||||
For a systemd agent, inspect the recent journal **locally on the affected node**:
|
||||
|
||||
```bash
|
||||
sudo journalctl -u pulse-agent.service --since '15 minutes ago' -n 200 --no-pager --output=cat
|
||||
```
|
||||
|
||||
Look for **Connected and registered with Pulse command server**, or
|
||||
**WebSocket connection failed repeatedly, reconnecting** and its error. A
|
||||
`dial websocket` error is a connection/handshake failure; `registration failed`
|
||||
means registration was attempted but not accepted. Scope alone does not prove
|
||||
that the credential's host/agent binding was admitted. No matching entry is
|
||||
inconclusive: initial retries may be debug-only; do not restart the host or
|
||||
enable server-wide debug logging to manufacture an error.
|
||||
|
||||
If reporting the problem, share only the failure stage and redacted error
|
||||
reason (or say no command-channel entry is visible), not the full journal or
|
||||
service configuration. Omit tokens, cookies, URLs, hostnames, addresses and
|
||||
agent/token IDs. Keep saved identity and credentials intact while distinguishing
|
||||
connection failures from admission failures; do not delete state, loosen TLS
|
||||
verification or broaden permissions to force a connection. Guest-local Docker
|
||||
monitoring with commands disabled remains an alternative to host-side discovery.
|
||||
|
||||
### Check Status
|
||||
```bash
|
||||
# Linux
|
||||
|
|
|
|||
|
|
@ -20,7 +20,10 @@ SECRET = "synthetic-docker-docs-secret"
|
|||
|
||||
def section(heading):
|
||||
guide = (ROOT / "docs/UNIFIED_AGENT.md").read_text()
|
||||
return guide.split("### " + heading + "\n", 1)[1].split("\n### ", 1)[0]
|
||||
marker = "### " + heading + "\n"
|
||||
if marker not in guide:
|
||||
raise AssertionError(f"missing diagnostic section: {heading}")
|
||||
return guide.split(marker, 1)[1].split("\n### ", 1)[0]
|
||||
|
||||
|
||||
def command(heading):
|
||||
|
|
@ -106,6 +109,52 @@ class DockerTroubleshootingDocsTest(unittest.TestCase):
|
|||
self.assertIn(operation, recipe)
|
||||
self.assertIn(operation, source)
|
||||
|
||||
def test_command_channel_guidance_does_not_confuse_scope_with_admission(self):
|
||||
text = section("Commands enabled but remote control blocked")
|
||||
for required in (
|
||||
"no admitted command channel connected", "not a connected session",
|
||||
"Automatic updates ready", "Changing Proxmox API permissions cannot",
|
||||
"locally on the affected node", "`dial websocket`", "`registration failed`",
|
||||
"No matching entry is\ninconclusive", "not the full journal",
|
||||
"Omit tokens, cookies, URLs, hostnames, addresses", "Keep saved identity and credentials intact",
|
||||
"do not delete state, loosen TLS", "commands disabled remains an alternative",
|
||||
):
|
||||
with self.subTest(required=required):
|
||||
self.assertIn(required, text)
|
||||
for label in ("Connected and registered with Pulse command server",
|
||||
"WebSocket connection failed repeatedly, reconnecting"):
|
||||
self.assertIn(label, text)
|
||||
self.assertIn(label, (ROOT / "internal/hostagent/commands.go").read_text())
|
||||
policy = (ROOT / "internal/api/connections_aggregator.go").read_text()
|
||||
self.assertIn("agent reports command execution enabled, but no admitted command channel is connected", policy)
|
||||
guest = section("Docker visible in one LXC but missing in another")
|
||||
self.assertIn("#commands-enabled-but-remote-control-blocked", guest)
|
||||
self.assertIn("do not repeat the guest probe", guest)
|
||||
self.assertNotRegex(text, r"--property=Environment|systemctl (?:cat|restart)|--insecure")
|
||||
|
||||
def test_command_channel_journal_check_is_bounded_and_read_only(self):
|
||||
recipe = command("Commands enabled but remote control blocked")
|
||||
with tempfile.TemporaryDirectory() as temporary:
|
||||
root = Path(temporary)
|
||||
for name, body in (
|
||||
("sudo", '#!/bin/sh\nexec "$@"\n'),
|
||||
("journalctl", '#!/usr/bin/python3\nimport json, sys\nfrom pathlib import Path\n'
|
||||
'Path("' + str(root / "argv.json") + '").write_text(json.dumps(sys.argv[1:]))\n'
|
||||
'print("WebSocket connection failed repeatedly, reconnecting")\n'),
|
||||
):
|
||||
path = root / name
|
||||
path.write_text(body)
|
||||
path.chmod(0o700)
|
||||
env = dict(os.environ, PATH=f"{root}:{os.environ['PATH']}", SYNTHETIC_SECRET=SECRET)
|
||||
result = subprocess.run(["bash", "-eu", "-c", recipe], env=env,
|
||||
capture_output=True, text=True, timeout=5)
|
||||
self.assertEqual(result.returncode, 0, result.stderr)
|
||||
self.assertEqual(json.loads((root / "argv.json").read_text()), [
|
||||
"-u", "pulse-agent.service", "--since", "15 minutes ago", "-n", "200",
|
||||
"--no-pager", "--output=cat",
|
||||
])
|
||||
self.assertNotIn(SECRET, result.stdout + result.stderr)
|
||||
|
||||
def run_guest(self, *, socket="present", docker="ok", pct="ok", cli=True):
|
||||
with tempfile.TemporaryDirectory() as temporary:
|
||||
root = Path(temporary)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue