GMI Sandbox SDK Reference
Python SDK for the GMI Sandbox control plane and sandbox data plane.Installation
Configuration
The client reads these environment variables when explicit arguments are not provided:Client
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:
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()
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()
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 aready 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 requireconnect() first.
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
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:
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()):
"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:
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
idc_name is reused automatically when present in the template response.
Builds and Logs
Product Specifications
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 aPage 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:
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.