Skip to main content

Linkspan configuration

This page lists everything that configures a Linkspan process, for writing a job script or a launching client, or reading a log line that begins fatal:. Flags are registered in main.go; transport arguments are parsed in internal/tunnel/link and internal/tunnel/devtunnel.

Flags​

Flags use Go's flag package: -x and --x are equivalent, and a value may be given as --flag=v or --flag v.

FlagDefaultDescription
--port8080Control port, the API's TCP port on 127.0.0.1; 0 picks a free one
--socketUnix socket that also serves the API, mode 0600; alone, it replaces the port
--workflowWorkflow YAML file
--tunnel-enablefalseCarry the API off the node over --tunnel-mode
--tunnel-modelink, devtunnel or both, comma-separated
--tunnel-link-args"--url <ws or wss URL>" of Airavata's link endpoint
--tunnel-devtunnel-args"--id <Dev Tunnel id> --cluster <Dev Tunnels region>"
--versionPrint the version and exit
-h, --helpPrint the flag list to stderr and exit 0

--tunnel-mode is required with --tunnel-enable, and each transport's args with that transport; each is refused without the other (Validation). The transport arguments are themselves flags, parsed the same way: --tunnel-link-args="--url=wss://…" is valid.

--version prints a bare X.Y.Z or X.Y.Z.<commit> as the only line on stdout. A plain go build reports dev, which Airavata's version check refuses.

Listeners​

The API asks for no credential, so the listener is the access control: a loopback port admits every user on the node, the socket only the job's user. On a shared node, prefer --socket.

Listener flagsListens on
Neither127.0.0.1:8080
--port127.0.0.1:<port>
--socketThe socket only
BothBoth, with the same routes

Each listener logs http: listening on <addr>; with --port 0 the line names the chosen port. Servers log the same line under their kind (sshd, jupyter, terminal). At the --socket path, Linkspan replaces any existing socket, even one another process still serves, and refuses any other file. It removes the socket on exit.

A Unix socket connects only on its node. A caller elsewhere in the cluster reaches it through a job step:

srun --jobid=<job id> --overlap curl --unix-socket ~/.cybershuttle/linkspan.sock http://localhost/api/v1/usage

The devtunnel transport carries only the control port. With --socket alone it starts, but nothing answers through the tunnel; give it a --port.

Environment​

Linkspan reads these variables from the environment it is started in. An empty token is refused.

VariableRead by
LINKSPAN_LINK_TOKENThe link transport, which offers it as the WebSocket subprotocol link.<token>; required with link
LINKSPAN_TUNNEL_HOST_TOKENThe devtunnel transport, which passes it as --access-token to devtunnel host; required with devtunnel
JUPYTER_TOKENjupyter.sessions.start, as the token when the request names none
SHELLTerminals, as the shell ttyd runs (default sh)
HOMELocating ~/.cybershuttle
PATHFinding sh, curl, nvidia-smi and criu
HTTPS_PROXY, NO_PROXYLinkspan's own downloads of the devtunnel CLI and ttyd; the link ignores them and dials directly

Every child process, including Jupyter kernels and SSH commands, inherits Linkspan's whole environment.

CS_LINK_URL, CS_CONTROL_PORT, CS_DEVTUNNEL_ID and CS_DEVTUNNEL_CLUSTER are not read by Linkspan; Airavata's job script expands them into flags.

Files​

Linkspan writes only under ~/.cybershuttle/. Downloads are staged as <file>.part and renamed into place; HTTPS is their only verification. A file already present is never fetched again; delete it to force a new download.

PathContentsWritten
bin/uv, python/, cache/uv/, jupyter-env/uv, the Python 3.12 it downloads when needed, its cache, and the Jupyter environmentBy the first Jupyter setup
bin/devtunnelMicrosoft's CLIOn first use of the devtunnel transport
bin/ttydttyd 1.7.7On the first terminal
checkpoints/<id>/CRIU images and snapshot, the process's PID and stdio namesBy checkpoint.pause

The clients write bin/linkspan, logs/ and sessions/<id>/workflow.yaml; Home-directory space lists every file.

Validation​

Flags, transports and the workflow are validated before anything binds. A failure logs fatal: <message> and exits 1.

ConditionMessage
--tunnel-enable without --tunnel-mode, or the reverse--tunnel-mode is required with --tunnel-enable and refused without it
--tunnel-mode names an unknown, empty or repeated transport--tunnel-mode: "<x>" is not link or devtunnel, or is repeated
A listed transport without its args, or args for an unlisted one--tunnel-<name>-args is required with --tunnel-mode=<name> and refused without it
Link args other than one --url with a ws or wss scheme and a host--tunnel-link-args needs only --url, a ws or wss URL
No link tokenLINKSPAN_LINK_TOKEN is required with the link transport
Dev Tunnel args other than a non-empty --id and --cluster--tunnel-devtunnel-args needs only --id and --cluster
No host tokenLINKSPAN_TUNNEL_HOST_TOKEN is required with the devtunnel transport
Unreadable workflow fileworkflow: read: <err>
Invalid YAML or an unknown fieldworkflow: parse: <err>
No triggersworkflow: no tasks
Unknown momentworkflow: trigger <n>: unknown "<on>"
A trigger without stepsworkflow: trigger <n>: no steps
Unknown actionworkflow: trigger <n> (<step name>): unknown action "<action>"
A listener cannot bind: port in use, or a non-socket file at the socket pathtasks: listen: <err>

An unknown flag prints the error and the flag list to stderr and exits 2.

Lifecycle​

A Linkspan process runs through five stages:

  1. Validate flags, transports and the workflow.
  2. Start tasks: one HTTP listener per address, the usage sampler, one task per transport, then the workflow.
  3. Run until SIGINT or SIGTERM, or the first fatal task error, logged as fatal: <task id>: <err>.
  4. Run the workflow's stop trigger, with the API still up.
  5. Cancel every task and wait for it; each child's process group receives SIGKILL. Log stopped and exit.

Only some task failures end the process at stage 3:

FailureFatal
A transportNo: logs <transport>: <err> and redials
A workflow step, a listener, an SSH serverYes
A Jupyter server, terminal or processNo: recorded in its state

Signals and exit codes​

Slurm delivers signals to the job: SIGTERM when the job is cancelled or reaches its walltime, and the signal named in #SBATCH --signal ahead of the walltime.

SignalEffect
SIGINT, SIGTERMGraceful: stop steps, teardown, exit 0
SIGUSR1, SIGUSR2Runs the workflow's trigger for that signal; ignored without one
SIGHUPRuns the workflow's trigger for it; without one, ends Linkspan at once with no stop steps or teardown, and child processes survive in their own process groups

When Linkspan is the job's main process, its exit code is the job's:

Exit codeWhen
0A graceful signal, --version or --help
1A validation or listen error, a fatal task error, or a failing workflow step, including a stop step
2An unknown flag or a malformed flag value