podman
podman
¶
Podman backend for the .protocol container runtime.
This is the concrete default runtime. Every subprocess call that
ends in a podman invocation lives in this module — other layers
speak only through the protocol.
The public export is PodmanRuntime plus the argv helpers that
terok_sandbox.sandbox.Sandbox uses to assemble podman run
commands (which remain podman-specific for now; a krun backend will
replace Sandbox.run when Phase 3 lands).
GpuConfigError(message, *, hint=_CDI_HINT)
¶
Bases: RuntimeError
CDI/NVIDIA misconfiguration detected during container launch.
Store the CDI hint alongside the standard error message.
Source code in src/terok_sandbox/runtime/podman.py
hint = hint
instance-attribute
¶
PodmanContainer(name, *, runtime)
¶
Podman implementation of Container.
Cheap to construct — does not verify existence. Each property /
method does a fresh podman inspect or equivalent.
Source code in src/terok_sandbox/runtime/podman.py
name = name
instance-attribute
¶
state
property
¶
Lifecycle state ("running", "exited", ...) or None.
running
property
¶
Shortcut: state == "running".
image
property
¶
Handle to the image this container was created from, or None.
rw_size
property
¶
Writable-layer size in bytes, or None if unavailable.
Uses podman container inspect --size — expect a brief pause
for large containers while overlay diffs are computed.
__repr__()
¶
__eq__(other)
¶
__hash__()
¶
start()
¶
Start the container.
Every lifecycle failure — missing podman, timeout, or non-zero
exit — surfaces as RuntimeError so callers have a
single exception type to catch. The original exception is
preserved via __cause__ when applicable.
Source code in src/terok_sandbox/runtime/podman.py
stop(*, timeout=10)
¶
Stop the container, SIGKILL after timeout seconds.
Every lifecycle failure surfaces as RuntimeError; see
start for the rationale.
Source code in src/terok_sandbox/runtime/podman.py
wait(timeout=None)
¶
Block until the container exits; return its exit code.
Raises TimeoutError on timeout, RuntimeError on
podman wait failures or non-numeric output.
Source code in src/terok_sandbox/runtime/podman.py
copy_in(src, dest)
¶
Copy a host path into the (stopped) container at dest.
Directories are copied contents-first (src/.) so existing
container contents at dest are preserved and augmented.
Source code in src/terok_sandbox/runtime/podman.py
login_command(*, command=_DEFAULT_LOGIN_COMMAND)
¶
Return an argv for os.execvp to attach interactively.
Empty command uses the default tmux session.
Source code in src/terok_sandbox/runtime/podman.py
logs(*, follow=False, tail=None)
¶
Return a context-managed iterator over decoded log lines.
stream_initial_logs(ready_check, timeout_sec)
¶
Stream logs until ready_check matches or timeout_sec elapses.
Prints each line to stdout as it arrives. Returns True when
the ready marker is observed, False on timeout.
Source code in src/terok_sandbox/runtime/podman.py
PodmanImage(ref, *, repository='', tag='', size='', created='')
¶
Podman implementation of Image.
Values listed by podman images (repository, tag, size,
created) may be pre-populated at construction to avoid an extra
inspect; when absent they fall back to empty strings.
Source code in src/terok_sandbox/runtime/podman.py
ref = ref
instance-attribute
¶
id
property
¶
Resolved image ID, or None when the image is absent.
repository
property
¶
Repository portion (pre-populated or "").
tag
property
¶
Tag portion (pre-populated or "").
size
property
¶
Podman-rendered size string (pre-populated or "").
created
property
¶
Podman-rendered creation timestamp (pre-populated or "").
__repr__()
¶
__eq__(other)
¶
__hash__()
¶
exists()
¶
Return True if the image is present locally.
Source code in src/terok_sandbox/runtime/podman.py
labels()
¶
Return the OCI Config.Labels as a flat string dict.
Source code in src/terok_sandbox/runtime/podman.py
history()
¶
Return the CreatedBy string of each layer, top to bottom.
Source code in src/terok_sandbox/runtime/podman.py
remove()
¶
Remove the image; return True on success.
No force flag — an image referenced by a running container stays, which matches cleanup semantics (sweeping safe garbage, not reaping live state).
Source code in src/terok_sandbox/runtime/podman.py
PodmanLogStream(container_name, *, follow, tail)
¶
Iterator over podman log lines.
Wraps podman logs [-f] [--tail N] in a subprocess.Popen and
yields decoded lines. __exit__ terminates the child; calling
close() mid-iteration has the same effect.
Source code in src/terok_sandbox/runtime/podman.py
process
property
¶
Underlying Popen handle — exposed for callers needing low-level access.
__iter__()
¶
__next__()
¶
Read the next decoded log line; raise StopIteration at EOF.
Source code in src/terok_sandbox/runtime/podman.py
__enter__()
¶
__exit__(*exc)
¶
close()
¶
Terminate the underlying podman logs process and release its pipes.
Reaps the child (terminate → wait → kill fallback) and then
closes both parent-side file descriptors so repeated
container.logs() calls do not leak FDs. Safe to call
multiple times; second call is a no-op.
Source code in src/terok_sandbox/runtime/podman.py
PodmanPortReservation(host='127.0.0.1')
¶
Holds a TCP port open until released.
Bind on construction; the reserved port number is exposed via the
port attribute. Caller is responsible for closing (directly via
close or via with).
Source code in src/terok_sandbox/runtime/podman.py
PodmanRuntime
¶
The default ContainerRuntime — talks to the podman CLI.
container(name)
¶
containers_with_prefix(prefix)
¶
Return handles for every container whose name starts with prefix-.
Single podman ps -a call under the hood; the returned handles
are lazy (fresh inspect on property access).
Source code in src/terok_sandbox/runtime/podman.py
image(ref)
¶
images(*, dangling_only=False)
¶
Enumerate local images.
dangling_only narrows to untagged <none>:<none> entries.
Source code in src/terok_sandbox/runtime/podman.py
exec(container, cmd, *, timeout=None)
¶
Run cmd inside container via podman exec.
Lets FileNotFoundError (podman missing) and
subprocess.TimeoutExpired propagate unchanged.
Raises ValueError if cmd is empty — podman exec with
no argv is never a valid request and catching it here avoids a
later IndexError in the debug log.
Source code in src/terok_sandbox/runtime/podman.py
exec_stdio(container, cmd, *, stdin, stdout, stderr=None, env=None, timeout=None)
¶
Bridge byte streams to podman exec -i for cmd inside container.
Synchronous: spawns the child, runs three daemon pump threads
(one per direction) copying bytes until either side reaches
EOF or the child exits, joins the pumps, returns the exit code.
Async callers drive this via
run_in_executor.
Lets FileNotFoundError (podman missing) propagate. On
timeout, terminates the child (terminate → 2 s wait → kill) and
re-raises TimeoutExpired.
Source code in src/terok_sandbox/runtime/podman.py
force_remove(containers)
¶
Best-effort podman rm -f of each container.
Continues through individual failures. An already-absent container counts as removed — the post-condition holds.
Source code in src/terok_sandbox/runtime/podman.py
reserve_port(host='127.0.0.1')
¶
container_states(prefix)
¶
Return {container_name: state} for matching containers.
Optimisation over [c.state for c in containers_with_prefix(prefix)]
— single podman ps -a instead of N inspects. Backend-specific;
not part of the ContainerRuntime protocol.
Source code in src/terok_sandbox/runtime/podman.py
container_rw_sizes(prefix)
¶
Return {container_name: rw_bytes} for matching containers.
Single podman ps --size call — --size is expensive (overlay
diffs) but one bulk call beats N inspects. Backend-specific; not
part of the ContainerRuntime protocol.
Source code in src/terok_sandbox/runtime/podman.py
check_gpu_error(exc)
¶
Raise GpuConfigError if exc looks like a CDI/NVIDIA issue.
Does nothing if the error does not match any known CDI patterns.
Defensively handles both bytes and str stderr so callers
that ran subprocess with text=True are not punished with an
AttributeError on .decode.
Source code in src/terok_sandbox/runtime/podman.py
check_gpu_available()
¶
Return True when a CDI spec declares the nvidia.com/gpu kind.
Wizards call this to decide whether to offer the NVIDIA base image;
the on-launch check_gpu_error
path is the authoritative one and stays in place. Any failure
(missing podman, missing CDI dirs, unreadable spec) collapses to
False so callers can treat this as a pure yes/no signal.
Source code in src/terok_sandbox/runtime/podman.py
redact_env_args(cmd)
¶
Return a copy of cmd with sensitive -e KEY=VALUE args redacted.
Handles the two-arg form only (-e KEY=VALUE). Callers passing
sensitive values via single-arg forms (--env=...) must pre-redact.
Source code in src/terok_sandbox/runtime/podman.py
gpu_run_args(*, enabled=False)
¶
Return podman run args for NVIDIA GPU passthrough.
Source code in src/terok_sandbox/runtime/podman.py
bypass_network_args(gate_port)
¶
Return podman network args for running without shield.
Replicates shield's normal networking (reachable host.containers.internal)
without nftables rules. Dangerous fallback — all egress is unfiltered.