host.dockerHost

Docker container host.

A DockerContainerHost satisfies the otto Host protocol by delegating most operations through a parent host that runs the docker daemon. oneshot becomes parent.oneshot("docker exec ..."); get / put are two-step docker cp via the parent’s filesystem; interact opens a PTY-backed docker exec -it over the parent’s existing SSH connection.

run (and open_session / send / expect) use a persistent docker exec -it <ctr> sh session multiplexed on the parent’s SSH connection — shell state (cd, env vars, shell vars) persists across calls, matching LocalHost and UnixHost. oneshot stays stateless and concurrent-safe.

Persistent-shell support requires an SSH-based UnixHost parent. Local-host parents and telnet parents are rejected at session-open time — the per-call oneshot path still works against any parent.

class otto.host.dockerHost.DockerContainerHost(parent, container_id, project, service, compose_project, log=True, log_stdout=True, resources=<factory>)

Bases: BaseHost

A Docker container exposed as a first-class otto host.

Construction is normally done by otto.docker.compose after a successful docker compose up; tests instantiate it directly with a mocked parent.

parent : --is-rst--Host

The lab host running the docker daemon. Owns auth, hop chain, and the SSH connection used to reach the daemon. Typed as Host (the protocol) so the type-system surface stays narrow, but run / open_session / send / expect / interact additionally require an SSH-based UnixHost at runtime — they open a persistent docker exec channel on the parent’s asyncssh connection. oneshot and file transfer work against any parent.

container_id : --is-rst--str

Docker container id or unique name. Resolved by otto.docker.compose.compose_up() via docker compose -p <proj> ps -q <service>.

project : --is-rst--str

Owning project name (the repo’s settings name). Combined with parent and service to form the host id.

service : --is-rst--str

Compose service name (e.g. api).

compose_project : --is-rst--str

The -p value passed to docker compose for this stack. Stored so other commands (logs, ps, down) can scope correctly.

name : --is-rst--str

Human-readable host name. Filled in __post_init__().

id : --is-rst--str

Unique host id used as the key in Lab.hosts and on the CLI. Format: <parent_id>.<project>.<service>.

is_virtual : --is-rst--bool

Containers are always virtual by definition.

log : --is-rst--bool

Whether this host’s command/output should appear in logs.

log_stdout : --is-rst--bool

Whether output is mirrored to stdout in addition to log files.

resources : --is-rst--set[str]

Reservation tags. Containers participate in the same reservation system as UnixHosts; the compose module typically copies the parent’s tags so concurrent test runs serialize through reservations.

async oneshot(cmd, timeout=None)

Run a single command in the container via the parent.

Stateless and concurrent-safe — each call spawns a fresh docker exec. run() is the stateful counterpart that preserves shell state across calls.

Return type:

CommandStatus

async open_session(name)

Open a named persistent shell session inside the container.

Return type:

HostSession

async send(text)

Send raw text to the container’s persistent session.

Return type:

None

async expect(pattern, timeout=10.0)

Wait for a pattern in the container’s session output stream.

Return type:

str

async put(src_files, dest_dir)

Upload local files into the container.

Two-step: parent.put to a per-container staging dir, then docker cp from there into the container. The staging dir is cleaned up unconditionally so a failed transfer doesn’t leak.

Return type:

tuple[Status, str]

async get(src_files, dest_dir)

Download files from the container to the local machine.

Two-step: docker cp from the container into a per-container staging dir on the parent, then parent.get to the local dir.

Return type:

tuple[Status, str]

rebuild_connections()

Drop any persistent session so the next call reopens it.

Mirrors UnixHost.rebuild_connections() for the all_hosts() host.rebuild_connections() pattern that otto test --cov uses to refresh hosts after pytest installs a new event loop. The container host doesn’t own any raw transport (the parent does), but its _session_mgr may hold a ShellSession whose asyncssh process is bound to the old loop. Replacing the manager forces lazy re-opens against the parent’s freshly-rebuilt SSH connection.

Return type:

None

async close()

Stop background tasks and tear down the persistent session.

Repeater stops first so a periodic task can’t reopen the session mid-shutdown. The parent’s underlying connection is owned by the parent and is not closed here — but this host must close before its parent so the session’s docker exec channel can drain cleanly.

Return type:

None