testcontainers-cpp 0.2.0
Native C++20 Testcontainers over the Docker Engine API
Loading...
Searching...
No Matches
testcontainers::DockerClient Class Reference

A synchronous client for the Docker Engine HTTP API. More...

#include <testcontainers/docker/DockerClient.hpp>

Classes

class  Session
 While alive, THIS client instance keeps its daemon connection open across requests and reuses it for consecutive idempotent GET calls — all other requests keep opening fresh connections, so a stale-connection retry can never replay a side effect. More...
struct  PullRetry
 Bounded-retry policy for pull_image (see set_pull_retry). More...
struct  ContainerPathStat
 Metadata of a container path, decoded from the X-Docker-Container-Path-Stat header of a HEAD /containers/{id}/archive probe — a cheap existence/size check before a download (no archive is transferred). More...

Public Member Functions

 DockerClient (DockerHost host)
 Construct a client for an explicitly resolved host.
 DockerClient (const DockerClient &other)
DockerClientoperator= (const DockerClient &other)
 DockerClient (DockerClient &&other) noexcept
DockerClientoperator= (DockerClient &&other) noexcept
 ~DockerClient ()=default
const DockerHosthost () const noexcept
void set_transport_timeouts (const docker::TransportTimeouts &timeouts)
 Transport deadlines applied to every connection this client opens (a copy of the client carries its timeouts along).
const docker::TransportTimeoutstransport_timeouts () const noexcept
void set_pull_retry (const PullRetry &retry)
 Retry policy for pull_image: an HTTP 5xx reply to POST /images/create is retried up to attempts total tries with a doubling backoff — that status is how the daemon relays transient registry trouble (an auth-token endpoint blip, a 502 mid-handshake).
const PullRetrypull_retry () const noexcept
void set_max_response_body (std::optional< std::uint64_t > limit)
 Cap the response body size the BUFFERED request paths are willing to hold in memory — request(), logs(), the string copy_from_container — so a runaway reply becomes a DockerError instead of unbounded allocation.
std::optional< std::uint64_t > max_response_body () const noexcept
Response request (std::string_view method, std::string_view target, std::string_view body={}, const std::vector< std::pair< std::string, std::string > > &headers={})
 Perform an HTTP request against the daemon and return the full response.
bool ping ()
 GET /_ping — true if the daemon answers with a 2xx status.
std::string server_os ()
 GET /version — the daemon's operating system (the Os field, e.g.
bool is_windows_engine ()
 True when the daemon is running in Windows-containers mode (server_os() contains "windows", case-insensitive).
void pull_image (const std::string &image, const std::optional< RegistryAuth > &auth=std::nullopt)
 POST /images/create?fromImage=... — pull an image (blocks until done).
bool image_exists (const std::string &reference)
 GET /images/{reference}/json — true when reference ("name[:tag]" or an image ID) resolves on the daemon.
ImageInspect inspect_image (const std::string &reference)
 GET /images/{reference}/json — a structured snapshot of the image (reference is "name[:tag]", an image ID, or a digest).
std::string inspect_image_raw (const std::string &reference)
 GET /images/{reference}/json — the RAW response body (the full inspect JSON), so callers can read any field ImageInspect does not model.
void build_image (const std::string &context_tar, const docker::BuildOptions &options, const docker::BuildLogConsumer &consumer={})
 POST /build — build an image from a tar build context (context_tar, an application/x-tar body).
void build_image (const docker::BodyProducer &context, const docker::BuildOptions &options, const docker::BuildLogConsumer &consumer={})
 Streaming POST /build: context writes the tar build context incrementally into the sink it is handed, and each block goes out as one chunk of the request body — the context is never held in memory whole (GenericBuildableImage::build() streams host files this way).
std::string create_container (const CreateContainerSpec &spec, const std::optional< RegistryAuth > &auth=std::nullopt)
 POST /containers/create — returns the new container id.
void start_container (const std::string &id)
 POST /containers/{id}/start.
ContainerInspect inspect_container (const std::string &id)
 GET /containers/{id}/json — throws DockerError if the container is gone.
std::string inspect_container_raw (const std::string &id)
 GET /containers/{id}/json — the RAW response body (the full inspect JSON), so callers can read any field ContainerInspect does not model.
std::vector< ContainerSummarylist_containers (const std::vector< std::pair< std::string, std::string > > &label_filters, bool all=true)
 GET /containers/json filtered by label equality.
void stop_container (const std::string &id, std::optional< int > timeout_secs=std::nullopt)
 POST /containers/{id}/stop (optional grace period in seconds).
void remove_container (const std::string &id, bool force=true, bool remove_volumes=true)
 DELETE /containers/{id} — force-kill and remove anonymous volumes by default.
ContainerLogs logs (const std::string &id, const LogOptions &opts={})
 GET /containers/{id}/logs — fetch a snapshot of the container's logs and demultiplex the (non-TTY) stream into separate stdout / stderr text.
void follow_logs (const std::string &id, const LogOptions &opts, const LogConsumer &consumer)
 GET /containers/{id}/logs?follow=1 — stream the multiplexed logs, decoding frames and invoking consumer per chunk until the stream ends (container stops) or consumer returns false.
FollowEnd follow_logs (const std::string &id, const LogOptions &opts, const LogConsumer &consumer, std::chrono::steady_clock::time_point deadline)
 Deadline-bounded follow_logs: same streaming, but the wait for the next chunk is additionally bounded by the absolute deadline — when it passes, the stream is closed and DeadlineExpired reported instead of blocking until the container stops.
ExecResult exec (const std::string &id, const std::vector< std::string > &cmd)
 Run cmd inside the running container and capture its output and exit code, using default options.
ExecResult exec (const std::string &id, const std::vector< std::string > &cmd, const ExecOptions &opts)
 Run cmd inside the running container with opts (env / working dir / user / privileged / tty / stdin / detach) and capture its output and exit code.
ExecResult exec (const std::string &id, const std::vector< std::string > &cmd, const ExecOptions &opts, const LogConsumer &consumer)
 Streaming variant of exec: starts cmd with opts and delivers output to consumer incrementally as the daemon flushes it (blocking until the command finishes or consumer returns false).
ExecStreamResult exec (const std::string &id, const std::vector< std::string > &cmd, const ExecOptions &opts, const LogConsumer &consumer, std::chrono::steady_clock::time_point deadline)
 Deadline-bounded streaming exec: same incremental delivery, but feeding stdin and the wait for each next output chunk are additionally bounded by the absolute deadline — when it passes, the stream is closed and the result says DeadlineExpired instead of blocking until the command finishes.
void resize_exec (const std::string &exec_id, TtySize size)
 POST /exec/{exec_id}/resize — resize a STARTED tty exec's pseudo-TTY to size (the foreground command gets SIGWINCH and sees the new rows x columns).
void resize_container_tty (const std::string &id, TtySize size)
 POST /containers/{id}/resize — resize the pseudo-TTY of a container created with tty (the foreground process gets SIGWINCH).
void copy_to_container (const std::string &id, const CopyToContainer &source)
 PUT /containers/{id}/archive?path=/ — copy a host file, in-memory bytes, or a host directory tree into the container by extracting a tar at the root.
void copy_to_container (const std::string &id, const std::vector< CopyToContainer > &sources)
 Batched copy: ONE PUT /containers/{id}/archive whose tar carries the entries of all sources in order (later sources win on a target collision, exactly as consecutive single copies would).
std::string copy_from_container (const std::string &id, const std::string &container_path)
 GET /containers/{id}/archive?path=<container_path> — fetch the tar archive of the file or directory at container_path.
void copy_from_container (const std::string &id, const std::string &container_path, const docker::ByteSink &sink)
 Streaming download: the same GET /containers/{id}/archive, but the raw tar bytes are delivered to sink in blocks as they arrive instead of being buffered.
void copy_from_container_to (const std::string &id, const std::string &container_path, const std::filesystem::path &dest_dir)
 Download the file or directory at container_path and EXTRACT it into the host directory dest_dir (created if missing), streaming: each file's bytes go from the wire straight to disk.
ContainerPathStat container_path_stat (const std::string &id, const std::string &container_path)
 HEAD /containers/{id}/archive?path=... — stat a container path without downloading it (see ContainerPathStat).
std::string create_network (const std::string &name, const std::vector< std::pair< std::string, std::string > > &labels={})
 POST /networks/create — create a user-defined network, returning its id.
std::string create_network (const NetworkCreateSpec &spec)
 POST /networks/create from a full spec; returns the new network id.
std::vector< NetworkInspectlist_networks (const std::vector< std::pair< std::string, std::string > > &filters={})
 GET /networks?filters=... — list networks, one NetworkInspect per entry (the daemon leaves the attached-containers detail unpopulated in list responses).
NetworkInspect inspect_network (const std::string &id)
 GET /networks/{id} — a structured snapshot of a network (id may be a name or an id, as the Docker API accepts both): driver, flags, IPAM pools, options, labels, and the currently attached containers.
std::string inspect_network_raw (const std::string &id)
 GET /networks/{id} — the RAW inspect JSON for a network (id may be a name or an id, as the Docker API accepts both), so callers can read any field NetworkInspect does not model.
void connect_network (const std::string &network_id, const std::string &container_id, const std::vector< std::string > &aliases={})
 POST /networks/{id}/connect — attach an existing container, optionally with DNS aliases on this network.
void disconnect_network (const std::string &network_id, const std::string &container_id, bool force=false)
 POST /networks/{id}/disconnect — detach a container from a network.
void remove_network (const std::string &id)
 DELETE /networks/{id} — remove a network (204 expected).
std::string create_volume (const VolumeCreateSpec &spec)
 POST /volumes/create — create a named volume (201 expected), returning the daemon's Name for it.
VolumeInspect inspect_volume (const std::string &name)
 GET /volumes/{name} — inspect a volume (200 expected).
std::vector< VolumeInspectlist_volumes (const std::vector< std::pair< std::string, std::string > > &filters={})
 GET /volumes?filters=... — list volumes, one VolumeInspect per entry.
VolumePruneResult prune_volumes (const std::vector< std::pair< std::string, std::string > > &filters={})
 POST /volumes/prune?filters=... — batch-remove unused volumes, returning the daemon's report (deleted names + reclaimed bytes).
void remove_volume (const std::string &name, bool force=false)
 DELETE /volumes/{name}?force=<bool> — remove a volume (204 expected).

Static Public Member Functions

static DockerClient from_environment ()
 Construct a client using DockerHost::resolve().

Detailed Description

A synchronous client for the Docker Engine HTTP API.

By default each request opens a fresh connection to the daemon over the resolved transport (unix socket / Windows named pipe / TCP / TLS) — the correctness-first choice the Rust reference (bollard) also makes. A scoped Session opts one instance into keep-alive reuse for consecutive GETs (used internally by the wait-strategy polling loops, where the per-request TCP/TLS handshake actually costs); a process-wide connection pool is deliberately NOT provided (see docs/TODO.md for the analysis).

Constructor & Destructor Documentation

◆ DockerClient() [1/3]

testcontainers::DockerClient::DockerClient ( DockerHost host)
explicit

Construct a client for an explicitly resolved host.

◆ DockerClient() [2/3]

testcontainers::DockerClient::DockerClient ( const DockerClient & other)
inline

◆ DockerClient() [3/3]

testcontainers::DockerClient::DockerClient ( DockerClient && other)
inlinenoexcept

◆ ~DockerClient()

testcontainers::DockerClient::~DockerClient ( )
default

Member Function Documentation

◆ operator=() [1/2]

DockerClient & testcontainers::DockerClient::operator= ( const DockerClient & other)
inline

◆ operator=() [2/2]

DockerClient & testcontainers::DockerClient::operator= ( DockerClient && other)
inlinenoexcept

◆ from_environment()

DockerClient testcontainers::DockerClient::from_environment ( )
static

Construct a client using DockerHost::resolve().

◆ host()

const DockerHost & testcontainers::DockerClient::host ( ) const
inlinenoexcept

◆ set_transport_timeouts()

void testcontainers::DockerClient::set_transport_timeouts ( const docker::TransportTimeouts & timeouts)
inline

Transport deadlines applied to every connection this client opens (a copy of the client carries its timeouts along).

Endpoints known to be long-polling widen the io deadline internally (stop waits up to its grace period, build may have long silent steps); the streaming call sites (follow_logs, exec attach reads) disable it regardless — or, on their deadline-bounded overloads, re-arm it from the remaining budget instead.

◆ transport_timeouts()

const docker::TransportTimeouts & testcontainers::DockerClient::transport_timeouts ( ) const
inlinenoexcept

◆ set_pull_retry()

void testcontainers::DockerClient::set_pull_retry ( const PullRetry & retry)
inline

Retry policy for pull_image: an HTTP 5xx reply to POST /images/create is retried up to attempts total tries with a doubling backoff — that status is how the daemon relays transient registry trouble (an auth-token endpoint blip, a 502 mid-handshake).

Anything else fails on the first try: 4xx are permanent, an error embedded in the 200 progress stream is how daemons report a nonexistent image, and a transport deadline expiry (TransportTimeoutError) is never retried. attempts below 1 counts as 1. A copy of the client carries the policy along.

◆ pull_retry()

const PullRetry & testcontainers::DockerClient::pull_retry ( ) const
inlinenoexcept

◆ set_max_response_body()

void testcontainers::DockerClient::set_max_response_body ( std::optional< std::uint64_t > limit)
inline

Cap the response body size the BUFFERED request paths are willing to hold in memory — request(), logs(), the string copy_from_container — so a runaway reply becomes a DockerError instead of unbounded allocation.

std::nullopt (the default) keeps the historical no-limit behavior. The paths that manage their own reads (the sink download, copy_from_container_to, follow_logs, exec output, build progress) are not affected by the cap. A copy of the client carries the cap along.

◆ max_response_body()

std::optional< std::uint64_t > testcontainers::DockerClient::max_response_body ( ) const
inlinenoexcept

◆ request()

Response testcontainers::DockerClient::request ( std::string_view method,
std::string_view target,
std::string_view body = {},
const std::vector< std::pair< std::string, std::string > > & headers = {} )

Perform an HTTP request against the daemon and return the full response.

target is the path, sent VERBATIM (e.g. "/_ping", "/v1.43/containers/json") — this raw escape hatch does no API-version pinning; an unversioned path gets the daemon's default (newest) version. The typed methods below all pin their paths to the negotiated version.

◆ ping()

bool testcontainers::DockerClient::ping ( )

GET /_ping — true if the daemon answers with a 2xx status.

◆ server_os()

std::string testcontainers::DockerClient::server_os ( )

GET /version — the daemon's operating system (the Os field, e.g.

"linux" / "windows"). Cached process-wide on first success: the engine mode (Linux vs Windows containers) does not change mid-process. Throws DockerError if the daemon is unreachable or the response is malformed.

◆ is_windows_engine()

bool testcontainers::DockerClient::is_windows_engine ( )

True when the daemon is running in Windows-containers mode (server_os() contains "windows", case-insensitive).

Used to skip the Linux-only Ryuk reaper and to route engine-specific tests.

◆ pull_image()

void testcontainers::DockerClient::pull_image ( const std::string & image,
const std::optional< RegistryAuth > & auth = std::nullopt )

POST /images/create?fromImage=... — pull an image (blocks until done).

image is "name[:tag]" (tag defaults to "latest").

When auth is provided it is sent verbatim as X-Registry-Auth; otherwise credentials are auto-resolved from the Docker config for the image's registry. A public pull (no credentials found) is unaffected. Transient daemon/registry 5xx replies are retried per the pull_retry() policy (3 tries with a 1s-then-2s backoff by default — see set_pull_retry for what is and is not retried).

◆ image_exists()

bool testcontainers::DockerClient::image_exists ( const std::string & reference)

GET /images/{reference}/json — true when reference ("name[:tag]" or an image ID) resolves on the daemon.

A purely local check: no registry is contacted. Throws DockerError on any daemon error other than a 404.

◆ inspect_image()

ImageInspect testcontainers::DockerClient::inspect_image ( const std::string & reference)

GET /images/{reference}/json — a structured snapshot of the image (reference is "name[:tag]", an image ID, or a digest).

A purely local lookup: no registry is contacted. Throws DockerError if the image is absent (404 -> NotFoundError) or the daemon errors.

◆ inspect_image_raw()

std::string testcontainers::DockerClient::inspect_image_raw ( const std::string & reference)

GET /images/{reference}/json — the RAW response body (the full inspect JSON), so callers can read any field ImageInspect does not model.

Throws DockerError exactly like inspect_image.

◆ build_image() [1/2]

void testcontainers::DockerClient::build_image ( const std::string & context_tar,
const docker::BuildOptions & options,
const docker::BuildLogConsumer & consumer = {} )

POST /build — build an image from a tar build context (context_tar, an application/x-tar body).

Blocks until the build finishes. The build progress is decoded as it arrives: each output line goes to consumer (when set), so long builds are observable live. Throws DockerError on a non-200 status or a build error embedded in the streamed output — the error message carries the tail of the step output for debugging.

◆ build_image() [2/2]

void testcontainers::DockerClient::build_image ( const docker::BodyProducer & context,
const docker::BuildOptions & options,
const docker::BuildLogConsumer & consumer = {} )

Streaming POST /build: context writes the tar build context incrementally into the sink it is handed, and each block goes out as one chunk of the request body — the context is never held in memory whole (GenericBuildableImage::build() streams host files this way).

Response handling (live progress decoding, embedded-error detection, the widened silent-step deadline) matches the string overload; on a mid-upload rejection the daemon's error status is preferred over the raw transport error.

◆ create_container()

std::string testcontainers::DockerClient::create_container ( const CreateContainerSpec & spec,
const std::optional< RegistryAuth > & auth = std::nullopt )

POST /containers/create — returns the new container id.

If the image is missing (404), pulls it (threading auth through) and retries once.

◆ start_container()

void testcontainers::DockerClient::start_container ( const std::string & id)

POST /containers/{id}/start.

◆ inspect_container()

ContainerInspect testcontainers::DockerClient::inspect_container ( const std::string & id)

GET /containers/{id}/json — throws DockerError if the container is gone.

◆ inspect_container_raw()

std::string testcontainers::DockerClient::inspect_container_raw ( const std::string & id)

GET /containers/{id}/json — the RAW response body (the full inspect JSON), so callers can read any field ContainerInspect does not model.

Throws DockerError if the container is gone (404) or the daemon returns a non-200.

◆ list_containers()

std::vector< ContainerSummary > testcontainers::DockerClient::list_containers ( const std::vector< std::pair< std::string, std::string > > & label_filters,
bool all = true )

GET /containers/json filtered by label equality.

all includes stopped containers. label_filters become Docker's filters={"label":["k=v",...]}.

◆ stop_container()

void testcontainers::DockerClient::stop_container ( const std::string & id,
std::optional< int > timeout_secs = std::nullopt )

POST /containers/{id}/stop (optional grace period in seconds).

◆ remove_container()

void testcontainers::DockerClient::remove_container ( const std::string & id,
bool force = true,
bool remove_volumes = true )

DELETE /containers/{id} — force-kill and remove anonymous volumes by default.

◆ logs()

ContainerLogs testcontainers::DockerClient::logs ( const std::string & id,
const LogOptions & opts = {} )

GET /containers/{id}/logs — fetch a snapshot of the container's logs and demultiplex the (non-TTY) stream into separate stdout / stderr text.

Always a snapshot (follow=0); use follow_logs() to stream.

◆ follow_logs() [1/2]

void testcontainers::DockerClient::follow_logs ( const std::string & id,
const LogOptions & opts,
const LogConsumer & consumer )

GET /containers/{id}/logs?follow=1 — stream the multiplexed logs, decoding frames and invoking consumer per chunk until the stream ends (container stops) or consumer returns false.

Blocking: run on your own thread for background consumption. Always streams (follow=1). Throws DockerError if the initial response is not 200.

◆ follow_logs() [2/2]

FollowEnd testcontainers::DockerClient::follow_logs ( const std::string & id,
const LogOptions & opts,
const LogConsumer & consumer,
std::chrono::steady_clock::time_point deadline )

Deadline-bounded follow_logs: same streaming, but the wait for the next chunk is additionally bounded by the absolute deadline — when it passes, the stream is closed and DeadlineExpired reported instead of blocking until the container stops.

Returns why the stream ended. Used by the log wait strategy; also handy for "collect output for at most N seconds" consumers. Throws like the unbounded overload (a deadline that expires while CONNECTING or reading the response header surfaces as the transport's own TransportTimeoutError, not as DeadlineExpired).

◆ exec() [1/4]

ExecResult testcontainers::DockerClient::exec ( const std::string & id,
const std::vector< std::string > & cmd )

Run cmd inside the running container and capture its output and exit code, using default options.

Equivalent to the opts overload with a default-constructed ExecOptions.

◆ exec() [2/4]

ExecResult testcontainers::DockerClient::exec ( const std::string & id,
const std::vector< std::string > & cmd,
const ExecOptions & opts )

Run cmd inside the running container with opts (env / working dir / user / privileged / tty / stdin / detach) and capture its output and exit code.

Creates the exec (POST /containers/{id}/exec), starts it (POST /exec/{exec_id}/start) and reads the exit code (GET /exec/{exec_id}/json).

With opts.detach == true the command is only STARTED (fire-and-forget, docker exec -d): create + start are two plain round-trips, nothing is attached, and the returned ExecResult keeps its defaults — empty output and exit_code 0; the command is still running, so its real status is unknown. detach + stdin_data throws DockerError before any daemon interaction (nothing is attached, so there is no stdin to feed).

With opts.tty == false the returned stream is the multiplexed frame format and is demuxed into stdout_data / stderr_data. With opts.tty == true the stream is raw and unframed: all of it goes to stdout_data and stderr_data is left empty. When opts.stdin_data is set those bytes are written to the exec's stdin and the send side is then half-closed so a reader (e.g. cat) sees EOF; on a transport that cannot half-close (TLS, or a byte-mode named pipe) this throws DockerError instead of hanging the reader. The Windows named pipe to a real daemon half-closes fine (the daemon pipe is message-mode).

◆ exec() [3/4]

ExecResult testcontainers::DockerClient::exec ( const std::string & id,
const std::vector< std::string > & cmd,
const ExecOptions & opts,
const LogConsumer & consumer )

Streaming variant of exec: starts cmd with opts and delivers output to consumer incrementally as the daemon flushes it (blocking until the command finishes or consumer returns false).

With opts.tty == false the stream is demuxed and each chunk is reported with its LogSource; with opts.tty == true the raw stream is reported as LogSource::Stdout.

Returns an ExecResult whose exit_code is read from the exec inspect (0 when the command was still running after an early consumer stop — the deadline overload below reports that distinction); stdout_data / stderr_data are left empty (the output was delivered to consumer). opts.detach is rejected with a DockerError before any daemon interaction: a detached exec produces no output stream to deliver.

◆ exec() [4/4]

ExecStreamResult testcontainers::DockerClient::exec ( const std::string & id,
const std::vector< std::string > & cmd,
const ExecOptions & opts,
const LogConsumer & consumer,
std::chrono::steady_clock::time_point deadline )

Deadline-bounded streaming exec: same incremental delivery, but feeding stdin and the wait for each next output chunk are additionally bounded by the absolute deadline — when it passes, the stream is closed and the result says DeadlineExpired instead of blocking until the command finishes.

Stopping delivery does NOT kill the command: it keeps running inside the container, so the result's exit_code is present only when the exec inspect says the command had finished (virtually always the case after FollowEnd::StreamEnded; after an early stop it is a race). Deadline mechanics match the follow_logs overload: connecting, the create/start round-trips, and reading the response header run under the transport's io deadline, so an expiry there surfaces as TransportTimeoutError, not as DeadlineExpired; everything after the header — the stdin writes included — is the deadline's. opts.detach is rejected like the overload above.

◆ resize_exec()

void testcontainers::DockerClient::resize_exec ( const std::string & exec_id,
TtySize size )

POST /exec/{exec_id}/resize — resize a STARTED tty exec's pseudo-TTY to size (the foreground command gets SIGWINCH and sees the new rows x columns).

ExecOptions::on_started delivers the exec id at exactly the first moment this call is valid; the daemon rejects resizing an exec that has not started (and one whose command already exited). ExecOptions::console_size sets the INITIAL size without this call.

◆ resize_container_tty()

void testcontainers::DockerClient::resize_container_tty ( const std::string & id,
TtySize size )

POST /containers/{id}/resize — resize the pseudo-TTY of a container created with tty (the foreground process gets SIGWINCH).

The daemon rejects resizing a container without a TTY or one that is not running.

◆ copy_to_container() [1/2]

void testcontainers::DockerClient::copy_to_container ( const std::string & id,
const CopyToContainer & source )

PUT /containers/{id}/archive?path=/ — copy a host file, in-memory bytes, or a host directory tree into the container by extracting a tar at the root.

Entry names are the target normalized (leading '/' stripped; a Windows drive-rooted target like "C:\x" becomes "x"). A single-file source needs its parent directory to already exist in the container; a directory source creates the target chain itself. The tar is produced and uploaded in blocks (a chunked request body): host files are read as they go out, so the payload is never held in memory whole. Throws DockerError on failure (non-200, or the host source cannot be read).

◆ copy_to_container() [2/2]

void testcontainers::DockerClient::copy_to_container ( const std::string & id,
const std::vector< CopyToContainer > & sources )

Batched copy: ONE PUT /containers/{id}/archive whose tar carries the entries of all sources in order (later sources win on a target collision, exactly as consecutive single copies would).

One round-trip and one archive regardless of the source count; an empty vector is a no-op. Streams like the single-source overload; throws like it too.

◆ copy_from_container() [1/2]

std::string testcontainers::DockerClient::copy_from_container ( const std::string & id,
const std::string & container_path )

GET /containers/{id}/archive?path=<container_path> — fetch the tar archive of the file or directory at container_path.

Returns the raw tar bytes (extract with docker::extract_tar). Throws DockerError on 404 (no such container or path) or any non-200. Buffers the whole archive — for payloads that should not sit in memory use the sink overload or copy_from_container_to.

◆ copy_from_container() [2/2]

void testcontainers::DockerClient::copy_from_container ( const std::string & id,
const std::string & container_path,
const docker::ByteSink & sink )

Streaming download: the same GET /containers/{id}/archive, but the raw tar bytes are delivered to sink in blocks as they arrive instead of being buffered.

Status errors (404 -> NotFoundError) are thrown before the first block; an exception from sink aborts the download and propagates unchanged.

◆ copy_from_container_to()

void testcontainers::DockerClient::copy_from_container_to ( const std::string & id,
const std::string & container_path,
const std::filesystem::path & dest_dir )

Download the file or directory at container_path and EXTRACT it into the host directory dest_dir (created if missing), streaming: each file's bytes go from the wire straight to disk.

Regular files and directories are materialized (permission bits best-effort); symlinks and other special entries are skipped; an entry that would escape dest_dir (absolute path or "..") throws DockerError. A single-file path lands as dest_dir/<basename>; a directory path lands as dest_dir/<dirname>/... (Docker archives are rooted at the requested path's base name).

◆ container_path_stat()

ContainerPathStat testcontainers::DockerClient::container_path_stat ( const std::string & id,
const std::string & container_path )

HEAD /containers/{id}/archive?path=... — stat a container path without downloading it (see ContainerPathStat).

Throws NotFoundError on 404, DockerError on any other non-200 or an undecodable header.

◆ create_network() [1/2]

std::string testcontainers::DockerClient::create_network ( const std::string & name,
const std::vector< std::pair< std::string, std::string > > & labels = {} )

POST /networks/create — create a user-defined network, returning its id.

labels are emitted as the network's Labels map (e.g. for Ryuk reaping).

◆ create_network() [2/2]

std::string testcontainers::DockerClient::create_network ( const NetworkCreateSpec & spec)

POST /networks/create from a full spec; returns the new network id.

◆ list_networks()

std::vector< NetworkInspect > testcontainers::DockerClient::list_networks ( const std::vector< std::pair< std::string, std::string > > & filters = {})

GET /networks?filters=... — list networks, one NetworkInspect per entry (the daemon leaves the attached-containers detail unpopulated in list responses).

Each filters pair is {category, expression}, e.g. {"label", "key=value"} or {"name", "my-net"}. Distinct categories AND together; repeated label expressions also AND, while repeated name expressions OR (any-match). The daemon matches network names by SUBSTRING, so callers wanting an exact name must compare .name on the results. Throws DockerError on any non-200.

◆ inspect_network()

NetworkInspect testcontainers::DockerClient::inspect_network ( const std::string & id)

GET /networks/{id} — a structured snapshot of a network (id may be a name or an id, as the Docker API accepts both): driver, flags, IPAM pools, options, labels, and the currently attached containers.

Throws DockerError on any non-200 (NotFoundError on 404).

◆ inspect_network_raw()

std::string testcontainers::DockerClient::inspect_network_raw ( const std::string & id)

GET /networks/{id} — the RAW inspect JSON for a network (id may be a name or an id, as the Docker API accepts both), so callers can read any field NetworkInspect does not model.

Throws DockerError on any non-200 (NotFoundError on 404).

◆ connect_network()

void testcontainers::DockerClient::connect_network ( const std::string & network_id,
const std::string & container_id,
const std::vector< std::string > & aliases = {} )

POST /networks/{id}/connect — attach an existing container, optionally with DNS aliases on this network.

◆ disconnect_network()

void testcontainers::DockerClient::disconnect_network ( const std::string & network_id,
const std::string & container_id,
bool force = false )

POST /networks/{id}/disconnect — detach a container from a network.

force also detaches a container that is not running.

◆ remove_network()

void testcontainers::DockerClient::remove_network ( const std::string & id)

DELETE /networks/{id} — remove a network (204 expected).

◆ create_volume()

std::string testcontainers::DockerClient::create_volume ( const VolumeCreateSpec & spec)

POST /volumes/create — create a named volume (201 expected), returning the daemon's Name for it.

spec.labels are emitted as the volume's Labels map (e.g. for Ryuk reaping). Throws DockerError otherwise.

◆ inspect_volume()

VolumeInspect testcontainers::DockerClient::inspect_volume ( const std::string & name)

GET /volumes/{name} — inspect a volume (200 expected).

Throws DockerError on any non-200 (in particular 404 when the volume does not exist).

◆ list_volumes()

std::vector< VolumeInspect > testcontainers::DockerClient::list_volumes ( const std::vector< std::pair< std::string, std::string > > & filters = {})

GET /volumes?filters=... — list volumes, one VolumeInspect per entry.

Each filters pair is {category, expression}, e.g. {"label", "key=value"}, {"name", "my-vol"} (a substring match daemon-side), or {"dangling", "true"}. Distinct categories AND together; repeated label expressions also AND, while repeated name expressions OR (any-match). Throws DockerError on any non-200.

◆ prune_volumes()

VolumePruneResult testcontainers::DockerClient::prune_volumes ( const std::vector< std::pair< std::string, std::string > > & filters = {})

POST /volumes/prune?filters=... — batch-remove unused volumes, returning the daemon's report (deleted names + reclaimed bytes).

Filters as in list_volumes; {"label", "key=value"} restricts the sweep. Daemons at API 1.42+ prune only ANONYMOUS unused volumes by default — add {"all", "true"} to sweep named volumes too (pre-1.42 daemons reject that filter with a 400; their default prune already swept named volumes). A label-only filter therefore never removes named volumes on 1.42+ daemons. Throws DockerError on any non-200 (e.g. 409 while another prune runs).

◆ remove_volume()

void testcontainers::DockerClient::remove_volume ( const std::string & name,
bool force = false )

DELETE /volumes/{name}?force=<bool> — remove a volume (204 expected).

Throws DockerError on any non-204 (404 if absent, 409 if still in use).