Host configuration (hosts.json)¶
Persistent per-host connection tuning, declared in hosts.json. (For
per-invocation overrides, see Connection control; for the custom netcat backend,
see Netcat transfers.)
Connection options¶
Every host can be configured with a dedicated options object per network
protocol. The default-constructed options reproduce otto’s historical
defaults exactly, so existing hosts.json entries keep working without
changes. To tune a protocol, add the matching *_options object to
the host entry:
Object |
Protocol |
|---|---|
|
SSH sessions |
|
Telnet sessions |
|
SFTP transfers |
|
SCP transfers |
|
FTP transfers (aioftp) |
|
see Netcat transfers |
The same six tables are recognized in four places, layered from least to most specific:
Hardcoded defaults in
otto.host.options— what you get when no*_optionsis supplied anywhere.Per-host
*_optionsinhosts.json— the lab’s own values for a single host.Product
[host_preferences]in.otto/settings.toml— applied to every host whose id matches the selector regex. Product values win overhosts.json. See Product host preferences.CLI
--term/--transfer— final word, applied at invocation time.
Merging is per key between layers (1)–(3). A host that sets only
port in hosts.json still inherits connect_timeout from the
product preference, and so on down to the dataclass default. The
fully resolved options are baked into the UnixHost at construction
time.
For one-off tuning at the call site (e.g. a single test wants a
different port), pass an *_options= keyword to get_host() /
all_hosts(). See Per-call overrides on get_host() / all_hosts() in the cookbook.
SSH¶
Set non-standard port, enable strict host-key checking, and tune the connect timeout:
{
"ip": "10.10.200.12",
"element": "target",
"creds": { "admin": "secret" },
"ssh_options": {
"port": 2222,
"known_hosts": "/home/user/.ssh/known_hosts",
"connect_timeout": 5.0,
"keepalive_interval": 30
}
}
Anything supported by asyncssh.connect() but not surfaced as a
curated field is reachable via extra, which is forwarded verbatim:
{
"ssh_options": {
"extra": {
"config": ["/etc/ssh/otto_ssh_config"],
"proxy_command": "corkscrew proxy 8080 %h %p"
}
}
}
Port forwarding¶
Structured forwards are declarative and applied right after the
connection opens. Each list element maps straight to an
asyncssh.SSHClientConnection.forward_*_port call:
{
"ssh_options": {
"local_forwards": [
{"listen_host": "localhost", "listen_port": 8080,
"dest_host": "web.internal", "dest_port": 80}
],
"remote_forwards": [
{"listen_host": "", "listen_port": 9000,
"dest_host": "localhost", "dest_port": 22}
],
"socks_forwards": [
{"listen_host": "localhost", "listen_port": 1080}
]
}
}
For forwards that aren’t expressible in JSON (UNIX-socket forwards,
X11, custom subsystems), build the SshOptions in Python and supply
a post_connect async hook — see the
connection options cookbook.
Telnet¶
{
"telnet_options": {
"port": 2323,
"cols": 200,
"rows": 50,
"echo_negotiation_timeout": 1.0
}
}
Set auto_window_resize to true for interactive telnet sessions
to have otto install a SIGWINCH handler that sends NAWS updates on
every local terminal resize — remote TUIs (vi, top, less)
then reflow like they do under SSH. It defaults to off so that
automated runs produce deterministic output.
Embedded / UART-backed consoles — four extra fields matter when the
telnet endpoint is a QEMU -serial telnet: bridge rather than a Unix
telnetd (TelnetOptions):
write_chunk_size(default0) — split each command write into chunks of at most this many bytes.0sends the whole payload in one call (correct for a host-terminated shell). Set a positive value (e.g.64) for a UART-backed RTOS shell that overruns its console RX FIFO on a multi-KBllext load_hexline.write_chunk_delay(default0.0) — seconds to pause between chunks; ignored whenwrite_chunk_sizeis0.login(defaulttrue) — setfalsefor a bare-metal / RTOS shell with no login step; otherwise otto waits for alogin:prompt that never arrives and hangs the connection.login_prompt(default":"byte) — byte delimiter that ends the login / password prompts. The default matcheslogin:,Username:,Password:, etc.single_client_console(defaultfalse) — settruewhen the endpoint is a single-client console (e.g. Zephyrshell_telnet). Otto registers the transport so the embedded teardown can force-release the slot if a timed-out test left it half-open. Leavefalsefor ordinary multi-session telnetd.
SFTP, SCP, FTP, Netcat¶
{
"sftp_options": { "env": { "LANG": "C" } },
"scp_options": { "block_size": 65536, "preserve": true },
"ftp_options": { "port": 2121, "ssl": true, "socket_timeout": 30 }
}
SftpOptions, ScpOptions, and FtpOptions each carry an extra
dict that is forwarded verbatim to the underlying library (asyncssh,
aioftp) for any option not surfaced as a curated field. NcOptions
has no extra — all netcat knobs are curated fields.
Notable SFTP fields (SftpOptions): env
sets remote environment variables; send_env forwards named local
variables to the remote SFTP process.
Notable SCP fields (ScpOptions): recurse
(default true) controls directory recursion — set it false to
transfer a single file without descending; preserve carries mtime/atime/mode.
Notable FTP fields (FtpOptions): beyond
port, ssl, and socket_timeout, the impactful knobs are
connection_timeout (handshake), path_timeout (list/stat),
read_speed_limit / write_speed_limit (bytes/sec caps, null =
unlimited), and passive_commands (default ["epsv", "pasv"]).
Netcat has additional options and auto-detection strategies — see Netcat transfers.
SNMP monitoring block¶
A host that exposes metrics over SNMP rather than a shell carries an snmp
block (SnmpOptions) instead of (or alongside) the
*_options transport objects. The full field reference and a worked example
are in otto monitor — see the Configuring the snmp block in hosts.json
section.
Per-host toolchain¶
Each host can specify a toolchain that tells otto which gcov and
lcov binaries to use for coverage report generation. This is
essential when hosts run products built with different cross-compilers.
Add an optional toolchain object to the host entry in hosts.json:
{
"ip": "10.10.200.12",
"element": "target",
"board": "arm-board",
"creds": { "admin": "secret" },
"toolchain": {
"sysroot": "/opt/arm-toolchain"
}
}
Tool paths (gcov, lcov) are resolved relative to the sysroot.
The defaults are usr/bin/gcov and usr/bin/lcov, so setting just
sysroot is sufficient when the toolchain follows the standard layout.
For non-standard layouts, override individual paths:
{
"toolchain": {
"sysroot": "/opt/llvm-15",
"gcov": "bin/llvm-gcov-wrapper.sh",
"lcov": "bin/lcov"
}
}
When no toolchain is specified, otto uses the system-installed tools
(/usr/bin/gcov, /usr/bin/lcov). Otto can also auto-discover
the toolchain from .gcno files produced during compilation – see the
coverage guide for details.