Reach a job from another login node¶
A job's record lives on the login node that submitted it. From any other login node that shares
your home directory you can still run status, watch, cancel and the other job commands on it.
dunscaith finds the owning host from a pointer file and runs the command there over SSH.
What you need¶
- A home directory shared between login nodes (usually NFS), so the pointer is visible everywhere.
- SSH from one login node to another, as yourself, without a password prompt you cannot answer. An agent, a key, or an open ControlMaster connection all work.
- The same dunscaith binary at the same absolute path on the owning host. The pointer records the path the binary had when you submitted.
The owning host is named by its own hostname¶
The pointer records the owning host by its own hostname, never by a login alias such as
login.cluster.example that round-robins across several nodes. An alias would send the SSH hop to
whichever node it picked, not to the one holding the record. Where the OS hostname is not the name
other login nodes use, a site profile sets hosting.host
and dunscaith records and checks that name instead.
So submit checks, before it creates any record, that the name resolves to this host and nothing
else. It refuses when the name does not resolve, resolves to no address, or resolves to any
address this host does not have, which is what a shared alias looks like:
submit refused before any record was created: this host cannot be reached by its own name: "login" resolves to 10.0.0.6, which this host does not have, so other login nodes could not reach its jobs by the name dunscaith records
ways out:
- set hosting.host to a name other login nodes reach this node by (a site profile can set it)
- submit from a login node whose hostname resolves to that node alone
- ask the site to make "login" resolve to this host only (DNS or /etc/hosts), not to a shared alias
- see https://dunscaith.phpboyscout.uk/how-to/reach-a-job-from-another-login-node/
An OS hostname that resolves only to loopback addresses is refused too. Debian and Ubuntu write
127.0.1.1 <hostname> into /etc/hosts, so the name resolves on this host but tells no other
host where it is. Set hosting.host to the name the other login nodes use:
A name set in hosting.host that resolves only to loopback here passes, because the site has said
it is the right one. It must still not resolve to another host's address.
supersede makes the same check, since it writes a pointer too. There is no setting to skip it.
The check resolves the name from this host, so it cannot prove that every other login node resolves
it the same way.
Run the command¶
Nothing changes in how you type it:
dunscaith reads ~/.config/dunscaith/jobs/<job>. If the pointer says the record belongs to this
host, the command runs here. Otherwise it runs ssh <owning host> <binary> --x-forwarded=<token>
and relays the output and exit status back.
Three commands never forward:
| Command | Why |
|---|---|
submit |
It runs where you invoke it. |
supervise |
A forwarded supervisor would die with the SSH session. Log in to the owning host. |
stop --emergency |
It goes straight to the scheduler and needs neither the record nor the owning host. |
list, prune and reconcile take no job and act on the host you run them on. list reads only
pointers, so it works with the owning host down.
A forwarded command is not forwarded again. If it lands on a host that does not match the record
root's HOST identity (machine-id and hostname together), it refuses. The owning host also refuses
a forwarded submit or supervise, which only ever run where they are invoked, whatever global
flags such as --config come before the command name.
The record root follows the job¶
A job command uses the record root the job was submitted under, which its pointer names. A
forwarded command carries that root to the owning host, which checks its HOST identity against
that root and runs the command there. On the owning host itself the pointer's root is used too,
unless you pass --root, which then wins. So a job submitted with --root /somewhere is found by
status, cancel and the rest without repeating --root, from any login node.
Commands that take no job (reconcile, prune) still act on the root resolved from --root,
DUNSCAITH_ROOT, record.root and the default. See
Choose a record backing.
The authentication ladder¶
dunscaith tries SSH in a fixed order and stops at the first that works.
- Non-interactive.
ssh -o BatchMode=yes. This covers an agent, your keys and an open ControlMaster socket, and never waits for input. - Interactive, only after an authentication failure. If step 1 failed with
Permission deniedand dunscaith is attached to a terminal, it runs ssh again without BatchMode and lets ssh ask for your passphrase, password or one-time code itself. dunscaith writes no prompt of its own, so two-factor setups work unchanged. - Nothing else falls back. Any other failure ends the command with an error.
Passing --ci, setting CI=true or the ci configuration key turns step 2 off. A running
supervisor never forwards, so it never prompts. dunscaith does not use the OS keychain for SSH.
Understand the error¶
dunscaith classifies a failure from ssh's own log. The class decides whether the command might have run on the remote.
| Message | Class | Did the command run? |
|---|---|---|
could not authenticate to <host> over ssh |
auth | No |
host key for <host> could not be verified; run ssh <host> once by hand ... |
host key | No |
owning host <host> is unreachable |
unreachable (connect, DNS or key exchange failed) | No |
connection to <host> ended before the command reported a result |
dropped | Possibly |
For a command that changes things, the dropped message adds it may have run, check with
dunscaith status. dunscaith never retries a dropped write. Check the job before you repeat it.
When a read command (status, watch) finds the host unreachable, it also prints the job's last
known state from the pointer, and whether it is supervised, judged from the pointer's
supervised-at:
owning host login-0 unreachable; last known state of 01J...: running (none), outcome reached false
supervision Unattended, judged from the pointer off the owning host, which can lag by up to 5m0s
The state is whatever the owning host last wrote, and may be stale; the supervision judgement can lag by one refresh period (ten poll intervals). An authentication or host-key failure prints only its own error, since the host may be up.
If the owning host is down and you need the job stopped, use stop --emergency. It talks to the
scheduler directly, records no cancel, and says so: recovery may still occur.
Fix a host key failure¶
dunscaith never passes StrictHostKeyChecking=no or accept-new, and it never falls back after a
host-key failure. With =no, a changed key could still authenticate and run the command. Connect
once by hand, check the fingerprint with your administrators, and accept it:
Then repeat the dunscaith command. If the key has genuinely changed, remove the old entry
(ssh-keygen -R login-0) only once you know why.
Connection reuse and ControlPath¶
dunscaith asks ssh to share one connection between commands (ControlMaster=auto, kept open for
60 seconds after the last use), so watch then cancel authenticates once. The socket directory
is on local disk and never in your home, where ssh deletes a socket it cannot connect to:
$XDG_RUNTIME_DIR/dunscaith, whenXDG_RUNTIME_DIRis an absolute path outside$HOME;- otherwise
<tmp>/dunscaith-<uid>(normally/tmp/dunscaith-<uid>), where<tmp>follows$TMPDIR.
The directory is created with mode 0700. If it exists with another mode or owner, or if
<directory>/<40-character hash> would exceed 90 bytes, dunscaith turns reuse off
(ControlMaster=no), says why on stderr (ssh connection reuse is off, ...), and carries on. If
every forwarded command asks for authentication again, check the length of $XDG_RUNTIME_DIR and
$TMPDIR first.
ssh's own log (-E) normally goes in the same directory. When reuse is off for either reason,
dunscaith puts the log in a fresh private directory (mode 0700) under <tmp> instead, and removes
it when the command ends.
dunscaith adds -t when it is attached to a terminal, so Ctrl-C reaches the remote command. With
-t, the remote's stderr merges into stdout.
Other things that can go wrong¶
- Different versions. The two binaries must speak the same forwarding protocol, or the owning host refuses and names both versions. If the protocol matches but the versions differ, the command runs with a warning naming both.
- Output noise. Anything your shell startup files print on the remote is discarded; only dunscaith's own framed output is relayed. If the remote shell cannot find the binary, you see the tail of its stderr in the error.
- Closing the connection. If your local ssh goes away, or you cancel the local command, the
remote command sees its stdin close and drains as if it had received SIGHUP. Running a forwarded
command with no stdin (from cron, or with
< /dev/null) does not count: dunscaith keeps the remote's stdin open until the command ends.