Skip to main content

Runtime

Trait Runtime 

Source
pub trait Runtime: Send + Sync {
Show 49 methods // Required methods fn pull_image<'life0, 'life1, 'async_trait>( &'life0 self, image: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn pull_image_with_policy<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, image: &'life1 str, policy: PullPolicy, auth: Option<&'life2 RegistryAuth>, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait; fn create_container<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, id: &'life1 ContainerId, spec: &'life2 ServiceSpec, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait; fn start_container<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn stop_container<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, timeout: Duration, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn remove_container<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn container_state<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<ContainerState>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn container_logs<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, tail: usize, ) -> Pin<Box<dyn Future<Output = Result<Vec<LogEntry>>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn exec<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, id: &'life1 ContainerId, cmd: &'life2 [String], ) -> Pin<Box<dyn Future<Output = Result<(i32, String, String)>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait; fn get_container_stats<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<ContainerStats>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn wait_container<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<i32>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn get_logs<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<Vec<LogEntry>>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn get_container_pid<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<Option<u32>>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn get_container_ip<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<Option<IpAddr>>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; // Provided methods fn exec_stream<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, id: &'life1 ContainerId, cmd: &'life2 [String], ) -> Pin<Box<dyn Future<Output = Result<ExecEventStream>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait { ... } fn exec_pty<'life0, 'life1, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, _opts: ExecOptions, ) -> Pin<Box<dyn Future<Output = Result<ExecHandle>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait { ... } fn wait_outcome<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<WaitOutcome>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait { ... } fn wait_outcome_with_condition<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, _condition: WaitCondition, ) -> Pin<Box<dyn Future<Output = Result<WaitOutcome>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait { ... } fn rename_container<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, _new_name: &'life2 str, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait { ... } fn get_container_port_override<'life0, 'life1, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<Option<u16>>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait { ... } fn sync_container_volumes<'life0, 'life1, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait { ... } fn logs_stream<'life0, 'life1, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, _opts: LogsStreamOptions, ) -> Pin<Box<dyn Future<Output = Result<LogsStream>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait { ... } fn stats_stream<'life0, 'life1, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<StatsStream>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait { ... } fn pull_image_stream<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _image: &'life1 str, _auth: Option<&'life2 RegistryAuth>, ) -> Pin<Box<dyn Future<Output = Result<PullProgressStream>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait { ... } fn list_images<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<Vec<ImageInfo>>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait { ... } fn remove_image<'life0, 'life1, 'async_trait>( &'life0 self, _image: &'life1 str, _force: bool, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait { ... } fn prune_images<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<PruneResult>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait { ... } fn kill_container<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, _signal: Option<&'life2 str>, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait { ... } fn tag_image<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _source: &'life1 str, _target: &'life2 str, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait { ... } fn inspect_image_native<'life0, 'life1, 'async_trait>( &'life0 self, _image: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<ImageInspectInfo>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait { ... } fn image_history<'life0, 'life1, 'async_trait>( &'life0 self, _image: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<Vec<ImageHistoryEntry>>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait { ... } fn search_images<'life0, 'life1, 'async_trait>( &'life0 self, _term: &'life1 str, _limit: u32, ) -> Pin<Box<dyn Future<Output = Result<Vec<ImageSearchResult>>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait { ... } fn save_images<'life0, 'life1, 'async_trait>( &'life0 self, _names: &'life1 [String], ) -> Pin<Box<dyn Future<Output = Result<ImageExportStream>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait { ... } fn load_images<'life0, 'async_trait>( &'life0 self, _tar_bytes: Bytes, _quiet: bool, ) -> Pin<Box<dyn Future<Output = Result<LoadProgressStream>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait { ... } fn import_image<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _tar_bytes: Bytes, _repo: Option<&'life1 str>, _tag: Option<&'life2 str>, ) -> Pin<Box<dyn Future<Output = Result<String>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait { ... } fn export_container_fs<'life0, 'life1, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<ImageExportStream>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait { ... } fn commit_container<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, _opts: &'life2 CommitOptions, ) -> Pin<Box<dyn Future<Output = Result<CommitOutcome>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait { ... } fn inspect_detailed<'life0, 'life1, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<ContainerInspectDetails>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait { ... } fn pause_container<'life0, 'life1, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait { ... } fn unpause_container<'life0, 'life1, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait { ... } fn update_container_resources<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, _update: &'life2 ContainerResourceUpdate, ) -> Pin<Box<dyn Future<Output = Result<ContainerUpdateOutcome>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait { ... } fn top_container<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, _ps_args: &'life2 [String], ) -> Pin<Box<dyn Future<Output = Result<ContainerTopOutput>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait { ... } fn changes_container<'life0, 'life1, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<Vec<FilesystemChangeEntry>>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait { ... } fn port_mappings_container<'life0, 'life1, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<Vec<PortMappingEntry>>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait { ... } fn prune_containers<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<ContainerPruneResult>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait { ... } fn list_containers<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<Vec<RuntimeContainerSummary>>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait { ... } fn archive_get<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, _path: &'life2 str, ) -> Pin<Box<dyn Future<Output = Result<ArchiveStream>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait { ... } fn archive_put<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, _path: &'life2 str, _tar_bytes: Bytes, _opts: ArchivePutOptions, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait { ... } fn archive_head<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, _path: &'life2 str, ) -> Pin<Box<dyn Future<Output = Result<PathStat>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait { ... }
}
Expand description

Abstract container runtime trait

This trait abstracts over different container runtimes (containerd, CRI-O, etc.)

Required Methods§

Source

fn pull_image<'life0, 'life1, 'async_trait>( &'life0 self, image: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Pull an image to local storage

Source

fn pull_image_with_policy<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, image: &'life1 str, policy: PullPolicy, auth: Option<&'life2 RegistryAuth>, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Pull an image to local storage with a specific policy.

When auth is Some, the runtime uses those inline credentials for the pull (§3.10 of ZLAYER_SDK_FIXES.md). When auth is None, the runtime falls back to its existing credential-store lookup keyed by registry hostname (or anonymous access when no match exists).

Non-Docker runtimes may accept but ignore the auth argument — their OCI puller (zlayer-registry) already resolves credentials from the store by hostname, and inline auth is primarily a Docker-backend concern. Ignoring it is safe: callers that need inline auth should use the Docker runtime.

Source

fn create_container<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, id: &'life1 ContainerId, spec: &'life2 ServiceSpec, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Create a container

Source

fn start_container<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Start a container

Source

fn stop_container<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, timeout: Duration, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Stop a container

Source

fn remove_container<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Remove a container

Source

fn container_state<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<ContainerState>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Get container state

Source

fn container_logs<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, tail: usize, ) -> Pin<Box<dyn Future<Output = Result<Vec<LogEntry>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Get container logs as structured entries

Source

fn exec<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, id: &'life1 ContainerId, cmd: &'life2 [String], ) -> Pin<Box<dyn Future<Output = Result<(i32, String, String)>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Execute command in container

Source

fn get_container_stats<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<ContainerStats>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Get container resource statistics from cgroups

Returns CPU and memory statistics for the specified container. Used for metrics collection and autoscaling decisions.

Source

fn wait_container<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<i32>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Wait for a container to exit and return its exit code

This method blocks until the container exits or an error occurs. Used primarily for job execution to implement run-to-completion semantics.

Source

fn get_logs<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<Vec<LogEntry>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Get container logs (stdout/stderr combined)

Returns logs as structured entries. Used to capture job output after completion.

Source

fn get_container_pid<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<Option<u32>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Get the PID of a container’s main process

Returns:

  • Ok(Some(pid)) for runtimes with real processes (Youki, Docker)
  • Ok(None) for runtimes without separate PIDs (WASM in-process)
  • Err if the container doesn’t exist or there’s an error

Used for overlay network attachment and process management.

Source

fn get_container_ip<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<Option<IpAddr>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Get the IP address of a container

Returns:

  • Ok(Some(ip)) if the container has a known IP address
  • Ok(None) if the container exists but has no IP assigned yet
  • Err if the container doesn’t exist or there’s an error

Used for proxy backend registration when overlay networking is unavailable.

Provided Methods§

Source

fn exec_stream<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, id: &'life1 ContainerId, cmd: &'life2 [String], ) -> Pin<Box<dyn Future<Output = Result<ExecEventStream>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Execute a command in a container and stream stdout / stderr / exit events as they are produced.

The default implementation calls the buffered Runtime::exec and emits everything as a single Stdout event, a single Stderr event, and a final Exit event. Runtimes that support true streaming (e.g. Docker via bollard) override this to produce line-by-line events as the command runs.

The returned stream always terminates with exactly one ExecEvent::Exit as the final item on success. Errors that occur before the stream is returned (e.g. container not found, failure to create the exec) are surfaced via the outer Result; errors that occur mid-stream are logged by the runtime and the stream closes.

Source

fn exec_pty<'life0, 'life1, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, _opts: ExecOptions, ) -> Pin<Box<dyn Future<Output = Result<ExecHandle>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Start an interactive exec session against a container, returning an ExecHandle the caller drives concurrently with the running process.

Unlike Runtime::exec (which buffers stdout/stderr and returns only after the process exits) and Runtime::exec_stream (which streams line-by-line events one-way), exec_pty is the long-lived bidirectional entry point: when ExecOptions::tty is set the runtime allocates a pseudo-terminal pair and the returned ExecHandle::stream shuttles raw PTY bytes; when tty is false the stream still carries stdin/stdout/stderr but without PTY framing. The handle’s ExecHandle::resize channel mirrors Docker’s POST /exec/{id}/resize and the ExecHandle::exit future resolves with the process exit code once the runtime detects termination.

The default implementation returns AgentError::Unsupported. Backends that can host interactive execs (Docker via bollard’s start_exec with hijacked stream, Youki via libcontainer’s exec API, HCS via the Windows console) override this. Runtimes that have no notion of an interactive exec (WASM in-process, mocks that don’t need PTY traffic) should leave the default in place — callers then surface a clear error rather than degrade silently to a buffered exec.

Source

fn wait_outcome<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<WaitOutcome>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Wait for a container to exit and return a WaitOutcome with richer classification (exit code + reason + signal + finished_at timestamp).

The default implementation delegates to Runtime::wait_container and synthesizes a WaitReason::Exited result with no signal/timestamp. Runtimes that can distinguish OOM kills, signal deaths, or report a finished-at time (e.g. the Docker runtime, which has ContainerInspectResponse.state.oom_killed / .finished_at) should override this.

This is the legacy entry point that always uses WaitCondition::NotRunning. Callers that need to honour Docker’s condition= query parameter should use Runtime::wait_outcome_with_condition instead.

Source

fn wait_outcome_with_condition<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 ContainerId, _condition: WaitCondition, ) -> Pin<Box<dyn Future<Output = Result<WaitOutcome>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Wait for a container to reach a WaitCondition and return a WaitOutcome.

Mirrors Docker’s POST /containers/{id}/wait?condition=<...> semantics:

  • WaitCondition::NotRunning (the default) — block until the container is no longer running. Returns the exit-code outcome.
  • WaitCondition::NextExit — wait for the next observed exit, even if the container is already stopped at call time. The default implementation cannot distinguish “already stopped” from “next exit”, so it falls back to the same wait as NotRunning. Backends that can subscribe to runtime events (Docker via bollard’s wait stream) override this to honour the semantic.
  • WaitCondition::Removed — block until the container has been removed. The default implementation again falls back to a normal wait; the Docker runtime overrides it via bollard’s condition parameter.

Default implementation delegates to Runtime::wait_outcome for all conditions, ignoring the condition argument. This keeps existing runtimes (Youki, WASM, mocks) working without code changes.

Source

fn rename_container<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, _new_name: &'life2 str, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Rename a container. Mirrors Docker’s POST /containers/{id}/rename?name=<new> endpoint.

new_name is the requested human-readable name (without any leading /). Backends are expected to validate the name against their own constraints (e.g. uniqueness, allowed characters) and return an appropriate AgentError on rejection.

The default implementation returns AgentError::Unsupported. Runtimes that can rename a live container override this:

  • Docker — calls bollard’s rename_container with RenameContainerOptions { name }.
  • Youki — currently returns Unsupported because the libcontainer state-dir is keyed off the immutable ContainerId and renaming the on-disk layout safely while a container is alive would require coordination with the supervisor that owns the bundle path.
  • Other backends (WASM, HCS, mocks) inherit the Unsupported default.
Source

fn get_container_port_override<'life0, 'life1, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<Option<u16>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Get a runtime-assigned port override for a container.

Returns:

  • Ok(Some(port)) if the runtime assigned a dynamic port to this container
  • Ok(None) if the container should use the spec-declared endpoint port

This exists for runtimes where all containers share the host network stack (e.g., macOS sandbox). Without network namespaces, multiple replicas of the same service would conflict on the same port. The runtime assigns each replica a unique port and passes it via the PORT environment variable. The proxy then routes to container_ip:override_port instead of container_ip:spec_port.

Runtimes with per-container networking (overlay, VMs, Docker) return None.

Source

fn sync_container_volumes<'life0, 'life1, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Sync all named volumes associated with this container to S3.

Called after a container is stopped but before it is removed, giving the runtime a chance to flush persistent volume data to remote storage.

The default implementation is a no-op. Runtimes that support S3-backed volume sync (e.g., Youki with the s3 feature) override this.

Source

fn logs_stream<'life0, 'life1, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, _opts: LogsStreamOptions, ) -> Pin<Box<dyn Future<Output = Result<LogsStream>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Stream container logs as raw byte chunks tagged with their channel.

Mirrors the GET /containers/{id}/logs endpoint of the Docker Engine API: callers can request follow, tail, since/until time windows, per-channel filtering (stdout / stderr), and inline timestamps via LogsStreamOptions. Backends that demultiplex Docker’s stdcopy framing emit one LogChunk per frame; line-based runtimes emit one chunk per line.

The default implementation returns AgentError::Unsupported. Concrete runtimes override this with backend-specific streaming (bollard’s logs for Docker, log-file tailing for Youki/HCS, etc.). The stream is 'static so HTTP handlers can drive it independently of the trait-method borrow.

Source

fn stats_stream<'life0, 'life1, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<StatsStream>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Stream periodic resource-usage samples for a container.

Mirrors the streaming form of GET /containers/{id}/stats in the Docker Engine API: each yielded StatsSample is one full snapshot of CPU / memory / network / block-IO / pids counters at the moment it was taken. Sampling cadence is backend-defined (Docker emits one sample per second by default).

The default implementation returns AgentError::Unsupported. Backends that can produce this data implement it directly: Docker via bollard’s stats, Youki by polling cgroup stat files, MockRuntime by emitting a deterministic single sample.

Source

fn pull_image_stream<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _image: &'life1 str, _auth: Option<&'life2 RegistryAuth>, ) -> Pin<Box<dyn Future<Output = Result<PullProgressStream>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Pull an image, streaming progress events as layers are downloaded.

Mirrors the streaming form of POST /images/create in the Docker Engine API. Backends emit a series of PullProgress::Status events for in-flight layers, followed by exactly one PullProgress::Done event on success. Errors that occur mid-pull surface as Err items on the stream and terminate it.

auth carries inline credentials for this pull. When None, the runtime falls back to its credential-store lookup keyed by registry hostname (matching the semantics of Runtime::pull_image_with_policy).

The default implementation returns AgentError::Unsupported. Backends override this with their native streaming pull (bollard’s create_image for Docker, zlayer-registry for Youki).

Source

fn list_images<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<Vec<ImageInfo>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

List all images managed by this runtime’s image storage.

The default implementation returns AgentError::Unsupported — individual runtimes override this with backend-specific logic (bollard for Docker, zlayer-registry cache walk for Youki, etc.).

Source

fn remove_image<'life0, 'life1, 'async_trait>( &'life0 self, _image: &'life1 str, _force: bool, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Remove an image by reference from local storage.

When force is true, also removes the image even when other containers reference it. The default implementation returns AgentError::Unsupported.

Source

fn prune_images<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<PruneResult>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Prune dangling / unused images from local storage.

Returns a PruneResult describing what was removed. The default implementation returns AgentError::Unsupported.

Source

fn kill_container<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, _signal: Option<&'life2 str>, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Send a signal to a running container.

When signal is None, the runtime sends SIGKILL (matching Docker’s docker kill default). Backends validate the signal name and reject anything outside the standard POSIX set (SIGKILL, SIGTERM, SIGINT, SIGHUP, SIGUSR1, SIGUSR2).

Used by POST /api/v1/containers/{id}/kill and Docker-compat docker kill. The default implementation returns AgentError::Unsupported.

Source

fn tag_image<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _source: &'life1 str, _target: &'life2 str, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Create a new tag pointing at an existing image.

source is the reference to an already-cached image. target is the new reference to create — it must be a full reference (repository + tag).

Used by POST /api/v1/images/tag and Docker-compat docker tag. The default implementation returns AgentError::Unsupported.

Source

fn inspect_image_native<'life0, 'life1, 'async_trait>( &'life0 self, _image: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<ImageInspectInfo>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Inspect an image and return a Docker-shaped detail record.

Mirrors Docker’s GET /images/{name}/json. Backends translate their native inspect output into ImageInspectInfo; the API/Docker compat shim emits the JSON body. The default implementation returns AgentError::Unsupported so non-Docker backends keep compiling.

Source

fn image_history<'life0, 'life1, 'async_trait>( &'life0 self, _image: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<Vec<ImageHistoryEntry>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Return the parent-layer history for an image.

Mirrors Docker’s GET /images/{name}/history. The default implementation returns AgentError::Unsupported.

Source

fn search_images<'life0, 'life1, 'async_trait>( &'life0 self, _term: &'life1 str, _limit: u32, ) -> Pin<Box<dyn Future<Output = Result<Vec<ImageSearchResult>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Search a registry for images matching term.

Mirrors Docker’s GET /images/search. limit caps the number of returned items; 0 means “let the registry decide”. The default implementation returns AgentError::Unsupported.

Source

fn save_images<'life0, 'life1, 'async_trait>( &'life0 self, _names: &'life1 [String], ) -> Pin<Box<dyn Future<Output = Result<ImageExportStream>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Stream a tar archive containing one or more images.

Mirrors Docker’s GET /images/get?names=.... Multi-image archives dedupe shared layers. The default implementation returns AgentError::Unsupported.

Source

fn load_images<'life0, 'async_trait>( &'life0 self, _tar_bytes: Bytes, _quiet: bool, ) -> Pin<Box<dyn Future<Output = Result<LoadProgressStream>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Load images from a tar archive.

Mirrors Docker’s POST /images/load. tar_bytes is the uncompressed (or gzip-compressed) tar produced by Self::save_images. quiet suppresses progress events when set. The default implementation returns AgentError::Unsupported.

Source

fn import_image<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _tar_bytes: Bytes, _repo: Option<&'life1 str>, _tag: Option<&'life2 str>, ) -> Pin<Box<dyn Future<Output = Result<String>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Import a single image from a tar root filesystem.

Mirrors the fromSrc=-mode of Docker’s POST /images/create. tar_bytes is a tar of the root filesystem; repo/tag are the reference to apply to the resulting image. The default implementation returns AgentError::Unsupported.

Source

fn export_container_fs<'life0, 'life1, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<ImageExportStream>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Stream a tar archive of the container’s filesystem.

Mirrors Docker’s GET /containers/{id}/export. The default implementation returns AgentError::Unsupported.

Source

fn commit_container<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, _opts: &'life2 CommitOptions, ) -> Pin<Box<dyn Future<Output = Result<CommitOutcome>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Commit a container’s filesystem state to a new image.

Mirrors Docker’s POST /commit?container=.... opts carries the optional repo/tag/comment/author/pause/changes parameters. The default implementation returns AgentError::Unsupported.

Source

fn inspect_detailed<'life0, 'life1, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<ContainerInspectDetails>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Return rich inspect details for a container: published ports, attached networks, first IPv4, health, and most-recent exit code.

Runtimes implement this by translating the backend’s native inspect response (bollard’s ContainerInspectResponse for Docker) into the runtime-level ContainerInspectDetails struct. The API layer merges these fields into ContainerInfo on GET /api/v1/containers and GET /api/v1/containers/{id} (§3.15 of ZLAYER_SDK_FIXES.md).

The default implementation returns ContainerInspectDetails::default — an all-empty record, which the API layer treats as “this runtime doesn’t support rich inspect; skip all the extra fields”. This keeps non-Docker runtimes (Youki, WASM, Mock) backwards compatible; they can override this later if they gain equivalent inspect capability.

Source

fn pause_container<'life0, 'life1, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Pause all processes in the container by freezing its cgroup.

Mirrors Docker’s POST /containers/{id}/pause. After pause, the container’s processes are suspended in the kernel via the cgroup freezer; calls to Runtime::container_state still report Running but no instructions execute until Runtime::unpause_container.

The default implementation returns AgentError::Unsupported. Backends override this with their native pause API (bollard’s pause_container for Docker, libcontainer’s Container::pause for Youki).

Source

fn unpause_container<'life0, 'life1, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Resume a previously-paused container by thawing its cgroup freezer.

Mirrors Docker’s POST /containers/{id}/unpause. The default implementation returns AgentError::Unsupported.

Source

fn update_container_resources<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, _update: &'life2 ContainerResourceUpdate, ) -> Pin<Box<dyn Future<Output = Result<ContainerUpdateOutcome>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Update a running container’s resource limits and restart policy.

Mirrors Docker’s POST /containers/{id}/update. The fields on ContainerResourceUpdate are individually optional: backends apply only the fields that are Some and leave the rest of the container’s runtime configuration untouched. A fully-empty update short-circuits to a no-op (no cgroup writes, no warnings).

Returns a ContainerUpdateOutcome whose warnings vector surfaces non-fatal issues (e.g. “kernel memory limit is deprecated”, or “real-time scheduling not supported on this kernel”). Empty warnings ⇒ every requested field was applied.

The default implementation returns AgentError::Unsupported. Backends override this:

  • Docker — calls bollard’s update_container with a ContainerUpdateBody populated from the input.
  • Youki — writes the corresponding cgroup v2 files (cpu.weight, memory.max, pids.max, io.weight, cpuset.cpus, cpuset.mems) under <container_root>/cgroup and persists the new restart policy in the on-disk supervisor state.
  • Other backends (WASM, mocks) inherit the Unsupported default.
Source

fn top_container<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, _ps_args: &'life2 [String], ) -> Pin<Box<dyn Future<Output = Result<ContainerTopOutput>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

List the processes running inside a container (docker top).

ps_args is forwarded to the runtime as the ps(1) argument list when supported; an empty slice means “use the runtime’s default columns”. Mirrors Docker’s GET /containers/{id}/top?ps_args=<...>.

The default implementation returns AgentError::Unsupported.

Source

fn changes_container<'life0, 'life1, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<Vec<FilesystemChangeEntry>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Report changes to a container’s filesystem since it was created.

Mirrors Docker’s GET /containers/{id}/changes. Returns one FilesystemChangeEntry per added / modified / deleted path in the container’s writable layer. Runtimes that don’t compute layer diffs (e.g. youki, which uses raw bundle rootfs without a layered FS) return AgentError::Unsupported.

Source

fn port_mappings_container<'life0, 'life1, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, ) -> Pin<Box<dyn Future<Output = Result<Vec<PortMappingEntry>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Report the published port mappings for a container.

Mirrors Docker’s GET /containers/{id}/port. Returns one PortMappingEntry per (container-port, protocol, host-binding) triple. Containers with no published ports return an empty vector.

The default implementation returns AgentError::Unsupported.

Source

fn prune_containers<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<ContainerPruneResult>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Prune stopped containers from the runtime.

Mirrors Docker’s POST /containers/prune. Returns the IDs of containers that were removed plus the bytes reclaimed. The default implementation returns AgentError::Unsupported.

Source

fn list_containers<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<Vec<RuntimeContainerSummary>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Enumerate all containers known to this runtime, including stopped / exited ones (Docker’s list_containers(all=true) semantics).

Used by zlayer-api::handlers::standalone_reconcile on daemon boot to match persisted standalone-container records against the runtime’s actual inventory: entries the runtime no longer reports are pruned, surviving entries are re-registered in the ContainerIdMap, and runtime containers carrying a com.zlayer.container_id label that has no storage match are counted as orphans (logged but otherwise left alone).

The default implementation returns an empty list, which makes reconcile degrade to a label-blind pass: storage entries can still be probed individually via Runtime::container_state, but orphan detection is disabled until the backend overrides this method (Docker via bollard::list_containers, youki via state-dir walk).

Source

fn archive_get<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, _path: &'life2 str, ) -> Pin<Box<dyn Future<Output = Result<ArchiveStream>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Stream a TAR archive of the file or directory at path inside the container.

Mirrors Docker’s GET /containers/{id}/archive?path=<...>. The returned ArchiveStream yields raw application/x-tar bytes. Backends decide whether to materialize the archive in memory or stream it on the fly:

  • Docker — bollard’s download_from_container produces a chunked stream of TAR bytes; we forward it verbatim.
  • Youki — a rootfs walk under <bundle>/rootfs<path> produces a TAR archive in a worker task and streams it through an mpsc.
  • Other backends (WASM, mocks) inherit the Unsupported default.

The default implementation returns AgentError::Unsupported.

Source

fn archive_put<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, _path: &'life2 str, _tar_bytes: Bytes, _opts: ArchivePutOptions, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Extract a TAR archive into the container at path.

Mirrors Docker’s PUT /containers/{id}/archive?path=<...>. The runtime must extract tar_bytes (an uncompressed TAR archive) into path inside the container, honouring ArchivePutOptions.

path must already exist inside the container and must be a directory; if it does not exist the runtime returns AgentError::NotFound. Mismatched directory/non-directory replacements with no_overwrite_dir_non_dir=true return AgentError::InvalidSpec.

The default implementation returns AgentError::Unsupported.

Source

fn archive_head<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _id: &'life1 ContainerId, _path: &'life2 str, ) -> Pin<Box<dyn Future<Output = Result<PathStat>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Return stat metadata for the file or directory at path inside the container.

Mirrors Docker’s HEAD /containers/{id}/archive?path=<...>, which answers with the metadata that GET /archive would expose without materializing the TAR. Used by docker cp and the API layer to short-circuit on missing paths.

The default implementation returns AgentError::Unsupported.

Implementors§