Commands and files
Run shell commands in a sandbox and move files in and out of it
Both need a sandbox that is starting or running. Calls made while it starts wait for it; a stopped one answers 409 sandbox_not_running, so resume it first.
Run a command
A command runs in a shell, so pipes and && work. It runs in /home/user unless you pass cwd, relative to it.
const { result } = await zavu.sandboxes.commands.run(sandboxId, {
command: "pip install requests && python3 main.py",
cwd: "app",
timeoutSeconds: 90,
});
if (result?.timedOut) console.log("killed after 90 s");
console.log(result?.exitCode, result?.stdout, result?.stderr);
The call waits up to timeoutSeconds (default 30, max 120). Past it the command is killed, timedOut is true and exitCode is null. Output longer than the response holds is cut, and stdoutTruncated or stderrTruncated says so.
Run a long command in the background
For anything longer than two minutes (a build, a test suite, a server), pass background: true. The answer is 202 with a command id, at once.
const started = await zavu.sandboxes.commands.run(sandboxId, {
command: "npm ci && npm test",
background: true,
});
const commandId = started.command!.id;
// Later: its status and the last 1 MiB of each stream.
const { command } = await zavu.sandboxes.commands.retrieve(commandId, { sandboxId });
console.log(command.status, command.exitCode); // "running" null, then "finished" 0
status is running, finished, or unknown when the machine's process supervisor restarted and lost track of it; the output shown then is what was written to disk.
Files
Read, write, list and delete files under /home/user or /tmp, up to 5 MiB each. A relative path is relative to /home/user.
await zavu.sandboxes.files.write(sandboxId, {
path: "app/config.json",
content: JSON.stringify({ debug: true }),
});
const { file } = await zavu.sandboxes.files.read(sandboxId, { path: "app/config.json" });
console.log(file.content);
// Binary content goes as base64, both ways.
const { file: image } = await zavu.sandboxes.files.read(sandboxId, {
path: "out/chart.png",
encoding: "base64",
});
const { files, truncated } = await zavu.sandboxes.files.list(sandboxId, { path: "app" });
await zavu.sandboxes.files.delete(sandboxId, { path: "out", recursive: true });
A listing is one level, sorted by name, and truncated is true past 10,000 entries. Deleting a directory needs recursive=true. For anything bigger than 5 MiB, fetch it from inside the machine with a command (curl, git clone) instead of through the API.
Run a script at start
setupScript on create runs with bash once the machine is ready, as its user, with passwordless sudo. It runs in the background: it does not delay the start, and its output is not returned, so write to a file if you need it.
await zavu.sandboxes.create({
setupScript: "#!/bin/bash\ngit clone https://github.com/acme/app && cd app && npm ci > /tmp/setup.log 2>&1",
});
To start ready every time instead of setting up on each start, save the result as a snapshot.