Commands and terminals
Run a single command in a Workspace and get its output back, or open an interactive terminal in the guest. Both resume by themselves when the connection to the node drops. The examples use the Go SDK, the E2B SDK, and kibo. Programs that call ProcessService directly are covered in With the API.
Running commands
Run a command in the guest, receive its standard output and standard error, and wait for it to finish. This example lists the contents of the Volume. The Go example uses the client from Connect to ctrl:
session, err := dataplane.Open(client, workspaceID, dataplane.WithScopes(
ctrlv1.DataPlaneScope_DATA_PLANE_SCOPE_PROCESS,
))
if err != nil {
log.Fatal(err)
}
defer session.Close()
stream, err := session.StartProcess(ctx, &ctrlv1.StartRequest{
Argv: []string{"sh", "-c", "ls -la"},
WorkingDirectory: "/data",
Mode: &ctrlv1.StartRequest_Pipe{Pipe: &ctrlv1.ProcessPipeMode{}},
})
if err != nil {
log.Fatal(err)
}
defer stream.Close()
for stream.Receive() {
event := stream.Event()
switch {
case event.Output != nil:
os.Stdout.Write(event.Output.GetData())
case event.Exited != nil:
fmt.Println("exit code", event.Exited.GetExitCode())
}
}
if err := stream.Err(); err != nil {
log.Fatal(err)
}With the Go SDK and kibo, the command is not interpreted by a shell. When you need shell syntax, such as pipes or wildcards, write sh -c '...'. The E2B SDK takes one command string and runs it in a shell.
The E2B SDK throws CommandExitError when the command exits with a non-zero code. It carries exitCode.
The options of kibo workspace exec:
-w(--working-directory) and--userchoose where and as whom the command runs. See User and working directory.--exec-timeoutkills the command after the given duration. There is no time limit by default.- For every flag, see kibo workspace exec.
-i forwards your local standard input to the remote process and closes the remote standard input when it reaches the end. This example copies a local directory into the Volume:
tar czf - src | kibo workspace exec -i "$workspace_id" -- tar xzf - -C /dataExit codes
kibo workspace exec exits with the exit code of the remote process, as ssh does. A process killed by a signal gives 128 plus the signal number, and one killed by --exec-timeout gives 124.
When kibo itself fails, before or while following the command, it exits with 255. The error output names the cause. See kibo exit codes.
Opening a terminal
The kibo workspace terminal command opens an interactive terminal in the guest:
kibo workspace terminal "$workspace_id"To run a specific program in the terminal, give it after --:
kibo workspace terminal "$workspace_id" -- /bin/bash -l- Both your local standard input and standard output must be terminals.
- The initial size comes from your local terminal. To set it yourself, pass
--rowsand--columnstogether. --working-directoryand--userfollow the same rules as forexec. See User and working directory.- Exit codes are the same as for
exec.
Reconnection
When the connection to the node drops, exec and terminal resume automatically. They do not run the command again.
- Output produced while disconnected is filled in.
- Input that was not delivered is resent by position, with no duplicates.
- Retries last at most 30 seconds. If the session cannot be resumed, the command exits with
255.
Lost output
The guest keeps recent output so that a resumed command can fill in what it missed:
- Each output channel of each process keeps its most recent 1 MiB.
- All processes in the guest together keep at most 16 MiB or 1/16 of guest memory, whichever is smaller, and never less than 1 MiB.
- When the total is exceeded, the guest releases the buffers of other processes as a whole: exited processes first, then running processes whose latest output is oldest.
Output that is no longer kept when the command resumes cannot be recovered:
| Command | What happens |
|---|---|
exec | Writes to standard error which channel lost how many bytes, keeps receiving until the remote process ends, and then exits with 255. The error message includes the remote exit status. In --json output, the loss is a "type":"gap" record |
terminal | Shows a notice in the terminal and continues. The exit code is still the remote one |
User and working directory
Every request can choose which user it runs as in the guest, and process requests can also choose a working directory. File reads and writes choose their user by the same rules.
| Entry point | User | Working directory |
|---|---|---|
kibo workspace exec | --user | -w, --working-directory |
kibo workspace terminal | --user | --working-directory |
kibo workspace file subcommands | --user | Not applicable |
ProcessService/Start | user | working_directory |
FilesystemService requests | user | Not applicable |
/v1/files | Query parameter user | Not applicable |
Choosing the user
- Without a user, the request runs as the user the Template declares, or as root if the Template declares none.
rootexplicitly selects root.- The node checks any other user name against the Template's declaration.
- If the user the Template declares is unavailable in the guest, see Default user unavailable.
Working directory and relative paths
- Without a working directory, the process starts in the home directory of its user, such as
/home/useror/root. SettingHOMEas an environment variable, with-eor in theenvironmentofProcessService/Start, does not change this directory. - If the working directory does not exist, the request returns
not_found. - Working directories and file paths can be relative. They resolve against the home directory of the user: for the user
user,notes/a.txtmeans/home/user/notes/a.txt. - Paths in responses are always the resolved absolute paths.
- Relative paths need a guest of
v0.3.0or later. On an older guest, file requests accept only absolute paths, and relative working directories are not resolved against home. Restart the Workspace to enable relative paths.
Important
The home directory is not a path whose data is guaranteed to be kept. To run in the Volume, pass -w /data. See Guarantees and limits.
With the API
Programs run processes through ProcessService on the data plane. They need a data-plane credential with the PROCESS scope; see Requesting a session credential. kibo requests the credentials it needs by itself. For every method and message, see ProcessService.
Starting a process
ProcessService/Start starts a process and returns its output stream. The process does not end with the Start or Attach stream. After the stream drops, the process keeps running, and the caller subscribes again with Attach.
After the process exits, SendInput, CloseStdin, SendSignal, and Resize on it return failed_precondition with:
ErrorDetail.reasonset toCONFLICTstageset toUSING_PROCESS- no
input_offset
The result of the process still arrives through exited on the output stream. Rely on that, and do not treat this error as a session failure.
Resuming process streams
Calling Attach again fills in the output missed during the disconnect, as far as the guest still keeps it, and input can be resent safely. For how much output is kept, see Lost output. kibo and the E2B gateway do this automatically; see Reconnection and E2B compatibility.
Resuming needs a guest of v0.2.0 or later. On an older guest, Attach ignores resume_from and the subscription starts at the current position, with start equal to offset, and SendInput with input_offset returns unimplemented (UNSUPPORTED). Restart the Workspace to enable resuming.
To resume a stream:
- Track the position each channel has received: the
offsetof theProcessOutputEventplus the length of itsdata. - When the stream ends with
unavailableor a dropped connection afterattached, callAttachwith the same PID andincarnation, and give the position of each channel inresume_from. - The new
attachedgives astartfor each channel. The replay begins there and is followed by live output, continuous within the channel. Ifstartis greater than the position you requested, the bytes in between are no longer in the buffer, and the difference is the number of bytes lost. - Send
SendInputwithinput_offset, the position where this input begins in the process's input. On a resend, the part the process has already accepted is skipped and never written twice.
Input positions:
- The
input_offsetin a successfulSendInputresponse is the number of input bytes the process has accepted so far, which is the position of the next input. - The
input_offsetinattachedis the value at the moment of resuming. - If
input_offsetin a request is greater than the number of bytes the process has accepted, the request returnsfailed_precondition(CONFLICT), withErrorDetail.input_offsetset to the accepted count, and nothing is written.
Other rules:
- If a position in
resume_fromexceeds the number of bytes the channel has produced,Attachreturnsinvalid_argument, and the existing subscription is unaffected. - After the process exits, you can still resume while its result is retained: the missed output is replayed first, and then
exitedarrives. - When the buffers of a process were released early to keep the guest total,
starton resume is the position at the time of release. - If the credential has expired when you resume, request a new one and then resume.
- Some client libraries report the connection close that happens when a node switches to a new data-plane process as a protocol error. Treat it as a dropped connection and resume; see Stream interruptions.
Troubleshooting
Default user unavailable
- Symptom: The Workspace starts normally, but requests that specify no
user, or the user the Template declares, returnfailed_preconditionwithErrorDetail.reasonset toCONFLICT. They are not retryable, andmessagenames the user and the reason. The desktop is unavailable too, whilerootstill works. - Cause: The user the Template declares does not exist in the guest, has a uid or gid of 0, or has no home directory. Usually it was deleted or renamed inside the guest.
- Resolution: Run as
rootto restore the user, then restart the Workspace. The default user and the desktop come back with it.
Next steps
- Files: upload, download, and watch files in the guest.
- Services and ports: open web services and forward ports.
- Desktop: view and operate a graphical desktop.
- API overview: credentials and conventions for your own program.
Creating and listing
You create a Workspace from a Template with the Go SDK, the E2B SDK, or kibo workspace create, choosing its resources, network access, and Volume as you go. This page covers choosing a Template, the parameters of create, and finding Workspaces again in lists.
Files
Upload, download, and delete files in the guest, and watch a directory for changes. The examples use the Go SDK, the E2B SDK, and kibo workspace file. Programs transfer file content over /v1/files and manage directories with FilesystemService; see With the API.