Skip to main content

GMI Sandbox SDK Reference

Python SDK for the GMI Sandbox control plane and sandbox data plane.

Installation

The SDK requires Python 3.9 or newer.

Configuration

The client reads these environment variables when explicit arguments are not provided:

Client

Explicit configuration:
Constructor arguments: client.health() returns local client information:

Async client

AsyncSandboxClient mirrors the synchronous client. All operations that can perform network or file I/O are awaitable:
The async client accepts the same configuration arguments. Its optional transport must be an async callable returning RawResponse. Call await client.aclose() when the client is not managed by async with. aclose() closes only the transport the SDK owns. A transport supplied by the caller is never closed by the client; closing it is the caller’s responsibility. After aclose(), further requests raise TransportError rather than silently opening a new connection pool. Both clients accept http and https URLs only and re-validate that scheme on every redirect hop. The check does not limit which hosts a configured base_url may reach. A malformed URL in base_url or in a redirect Location, such as a non-numeric port or an invalid host name, raises TransportError and is not retried. Non-ASCII characters in the path and query are sent percent-encoded as UTF-8.

Basic Workflow

idc_name is optional for sandbox and template creation: when omitted, the service falls back to the organization’s configured default IDC.

Sandboxes

client.sandboxes.create()

Arguments: Returns a Sandbox.

client.sandboxes.list()

state accepts a string or a sequence of strings. Metadata is encoded as metadata[key] query parameters.

client.sandboxes.get()

client.sandboxes.connect()

The returned sandbox contains fresh data-plane connection fields.

Sandbox

Properties: Lifecycle states (SandboxStatus): provisioning, running, pausing, paused, resuming, checkpointing, updating, failed, deleting, and deleted. Methods:
refresh(), wait_until_running() and update_metadata() keep the data-plane connection fields returned by connect() (sandbox_access_token, traffic_access_token, domain); the sandbox detail and update responses do not include the access tokens. Data-plane calls (files, commands) raise ValueError if the sandbox has no access token; call connect() first. pause() keeps disk files except /tmp; memory and running processes are not kept. resume() is a cold start. Call connect() again before data-plane calls. wait_until_running() raises TerminalStateError (a RuntimeError) as soon as the sandbox is failed, deleting or deleted, or is paused (a resume that did not complete); it does not wait out the timeout for states that cannot become running. set_timeout() resets the time-to-live and returns the sandbox with end_at set to the new expiry. In some IDCs the access token is bound to the previous end_at, so call connect() again after extending the lifetime; where the token is not time-bound, connect() returns the same token.

Snapshots

A snapshot is a durable copy of a running sandbox. Launch new sandboxes from a ready snapshot with client.sandboxes.create(snapshot_id=...).
Snapshot properties: snapshot_id (alias id), name, idc_name, source_sandbox_id, status, data. Snapshot statuses (SnapshotStatus): creating, ready, error, deleting, and delete_failed. A deleted snapshot is no longer returned: reading it raises NotFoundError. wait_until_ready() raises TerminalStateError (a RuntimeError) on error, deleting or delete_failed, including status_reason when the service supplies one. snapshot.delete() raises ConflictError while a sandbox launched from the snapshot is still active; delete those sandboxes first. A paused sandbox cannot be snapshotted (ConflictError); resume it first.

Files

All file methods use the sandbox data plane and require connect() first.
Methods: download() always returns bytes. destination is an additional local write. Both read() and download() buffer the complete response in memory; use byte_range with download() when retrieving large files in chunks. upload_tree() reuses the 512 MiB packed-size limit and skips symlinks that resolve outside the local directory. It uploads one archive, unpacks it with the sandbox command API under /bin/sh (so images without bash work), and removes the temporary archive. timeout bounds both the client wait and how long the sandbox lets the unpack run (at most 3600 seconds). If the unpack fails, it raises TerminalStateError (a SandboxSDKError and a RuntimeError) with the exit code and stderr; .state holds the execution status.

Command Execution

Arguments: Execution properties:
stdout and stderr are each capped at 1 MiB. When a stream is cut, stdout_truncated / stderr_truncated is True; redirect large output to a file and read it with sandbox.files.download(..., byte_range=...). Execution statuses (ExecutionStatus): pending, running, cancelling, succeeded, failed, cancelled, and timed_out. timed_out is terminal: the command outlived execution_timeout_seconds. Methods:
Cancel only non-terminal executions. The service may reject cancellation after an execution has completed. If wait() times out but the execution finishes before its cancel lands, it returns the finished execution instead of raising. Otherwise it raises WaitTimeoutError, even when the cancel itself fails; the cancel error is available as __cause__. The synchronous POST /executions wait window is capped at approximately 25 seconds. Run with wait=False, then call Execution.wait() for longer work, and set execution_timeout_seconds for anything that may run longer than 300 seconds: Execution.wait() only bounds how long the client waits, not how long the sandbox lets the command run.

Templates

Create

resources selects a catalog preset by product SKU (see client.product_specifications.list()):
Custom resources ("type": "custom") are currently rejected with 400 Request.InvalidParameter. Build sources include image and template sources:
idempotency_key is required for template creation: retrying with the same key and arguments replays the same Template instead of creating a second one. A retry after the Build already started is also safe; the SDK confirms the Build is past waiting and does not start it again. Rebuilds (templates.builds.create()) are not idempotent. Each call creates a new Build and supersedes the Template’s running Builds, so do not blindly retry one. Its idempotency_key is optional and only lets a retry reuse an uploaded build_context_dir; it is not sent with the rebuild itself. Dockerfile builds accept dockerfile_content, build_context_dir, and start_cmd in place of build:
Build contexts are uploaded as gzip-compressed tar archives (tgz) and are limited to 512 MiB before compression. Only the paths that COPY/ADD read are packed, and a .dockerignore at the root of build_context_dir is honored with Docker’s rules (*, **, ?, ! exceptions, last match wins). A COPY source excluded by .dockerignore raises ValueError. Symlinks that resolve outside build_context_dir are excluded from the archive. Unlike .gitignore, a pattern without / matches only at the root of build_context_dir: *.env excludes secret.env but not app/secret.env. Prefix **/ to match at any depth, for example **/*.env or **/node_modules. A trailing / is ignored, so temp/ also excludes a file named temp. This is the same as docker build. When the Dockerfile uses the context, the SDK performs the live API’s split flow: create the waiting Template/Build, initialize and upload a tgz context, poll until the file is ready, and start the existing Build. The API supports a single context file, so the SDK rewrites each local COPY/ADD into steps that unpack that file. Each instruction takes one source inside build_context_dir (a file or a directory, . for all of it) and one destination, in shell form or JSON form (COPY ["app.py", "/app/"]), and may span lines with a trailing backslash. $VAR and ${VAR} in the destination expand to ENV values. COPY/ADD flags such as --chown are rejected, and so are heredocs (RUN <<EOF), which the API does not support. When idc_name is omitted, templates.create() uses GMI_SANDBOX_IDC_NAME for every request it makes. templates.builds.create() targets an existing Template, so without idc_name it lets the API use that Template’s IDC. default_user (optional, for example {"username": "root"} or {"username": "app", "uid": 9999}) sets the runtime identity of sandboxes launched from the Build. The API applies it after all build steps, so it overrides the Dockerfile’s final USER, but not its WORKDIR. It is accepted with build= or dockerfile_content= on templates.create() and templates.builds.create(); passing a different default_user inside build, or passing it to templates.create() with neither build= nor dockerfile_content=, raises ValueError. Username and UID rules are enforced by the API. Returns a Template. The returned object can be used with template instance methods such as update(), delete(), builds(), build(), and build_logs(). Call template.wait_until_ready(timeout=300) to poll latest_build_status, the status of the most recently created build. It refreshes before every check, so it also waits for a rebuild started with templates.builds.create(). It returns at ready, raises TerminalStateError for failed terminal states, and raises WaitTimeoutError (a TimeoutError) while the build remains pending.

List and Get

Update and Delete

The template’s idc_name is reused automatically when present in the template response.

Builds and Logs

Product Specifications

An IDC is required: pass idc_name or set GMI_SANDBOX_IDC_NAME. Unlike sandbox and template creation, the organization’s default IDC does not apply, so a request with neither returns 400. include_unavailable=True also returns products whose status is unavailable.

Pagination

List methods return a Page object:
Page fields:

Errors

Errors from API calls, the HTTP transport and the wait helpers (wait_until_running(), wait_until_ready(), Execution.wait()) derive from SandboxSDKError. Invalid arguments, and data-plane calls made before connect(), raise the built-in ValueError or TypeError before any request is sent. Local file errors, such as a missing upload source or an unreadable build context, propagate unchanged as OSError (for example FileNotFoundError). Other 429 limits, such as the number of pending Template files, raise a plain RateLimitError. TransportError.phase is connect, write, or read when the transport can identify the failing phase; otherwise it is None. The synchronous client reports read for failures while waiting for or reading the response, and connect only for refused connections and DNS failures; it cannot tell a connect timeout from a write failure, so those have phase None. A request that fails in transport is attempted up to three times in total: GET and HEAD on any failure, other methods on connect failures, and DELETE also on any failure except read. A DELETE whose response was lost may already have run, so it raises TransportError instead of retrying into a NotFoundError; check the resource before deleting again. Because each attempt has its own timeout, a GET against a server that stops responding can take about three times timeout (plus a short backoff) before TransportError is raised. APIError fields:
Error handling example:

OpenAPI Coverage

The SDK maps the Sandbox-related OpenAPI operations as follows: Not available in the SDK yet: the interactive shell (launchSandboxShell, attachSandboxShell, controlSandboxShell) and sandbox network actions (executeSandboxAction). Call the HTTP API directly for these.