Zudoku
Sandboxes

Commands

A sandbox runs commands in two ways. exec runs a command to completion and returns its output. start returns at once and gives you a Command to control.

Run a command to completion

exec returns the exit code and both output streams:

TypeScriptCode
import { Sandbox } from "@unikraft/cloud"; await using sandbox = await Sandbox.create(); const result = await sandbox.exec("ls -la /etc"); console.log(result.exitcode); // 0 console.log(result.stdout);

Set the working directory and the environment

Each command takes its own cwd and env:

TypeScriptCode
const result = await sandbox.exec("npm test", { cwd: "/work/app", env: { CI: "1" }, });

Limit how long you wait

timeoutSeconds makes exec return when the time runs out. This isn't an error: you get the output so far, exitcode is null, and the command keeps running.

TypeScriptCode
const result = await sandbox.exec("make", { timeoutSeconds: 30 }); if (result.exitcode === null) { const build = sandbox.command(result.uuid); await build.wait(); console.log((await build.logs()).stdout); }

Start a long-running command

start doesn't wait. It returns a Command, and you decide what happens next: write to its standard input, wait for it, read its logs, or stop it.

TypeScriptCode
const server = await sandbox.start("cat", { cwd: "/work" }); await server.stdin("first line\n"); await server.stdin("last line\n", { eof: true }); await server.wait({ timeoutSeconds: 10 }); const logs = await server.logs(); console.log(logs.stdout); await server.delete();

Stop a command

signal sends a signal by name or by number:

TypeScriptCode
const server = await sandbox.start("sleep 3600"); await server.signal("TERM");

Read the output later

exec deletes the command record when the command finishes. Pass keep: true to keep it, so another part of your program can read the logs by UUID:

TypeScriptCode
const { uuid } = await sandbox.exec("make", { keep: true }); const logs = await sandbox.command(uuid).logs(); console.log(logs.stderr);

logsRaw reads one stream as bytes, and it takes a byte range. A negative offset reads from the end of the stream:

TypeScriptCode
const tail = await sandbox.command(uuid).logsRaw("stdout", { offset: -4096 }); console.log(new TextDecoder().decode(tail));

sandbox.commands() returns every command that the sandbox knows about, in start order.

Reference

Every method on Command is exactly one request, so you can see what a step costs. See Command and ExecOptions in the source for the complete list.

Last modified on