Date: 2026-05-11
Time: 15:44
This is an example script demonstrating FTL2's remote SSH streaming execution with real-time progress tracking. It shows how to execute modules on remote hosts over SSH while receiving live event callbacks (progress updates, log messages) — covering single-host, multi-host, and auto-staging workflows. All examples target a local Docker container as the SSH endpoint.
Run the full example suite:
uv run python example_remote_streaming.py
Prerequisites: A Docker container with SSH access must be running (docker-compose up -d).
Four progressively complex examples:
1. Basic SSH streaming — Run a raw shell command and capture JSON events emitted on stderr:
stdout, stderr, rc, events = await host.run_streaming(
'echo \'{"event": "log", ...}\' >&2; echo "output"',
event_callback=on_event,
)
2. Remote bundle execution — Build a module into a bundle, stage it on the remote host, then execute with progress display:
bundle = build_bundle(module_path, dependencies=[])
bundle_path = await stage_bundle_remote(host, bundle)
result = await execute_remote_streaming(host, bundle_path, {"steps": 5}, event_callback=display.handle_event)
3. Multi-host parallel execution — Run bundles on multiple hosts concurrently, each with its own progress bar:
callback = display.make_callback(host_name) # per-host progress
results = await asyncio.gather(*[run_on_host(name) for name in host_names])
4. Auto-staging — Combines staging and execution in one call:
result = await execute_remote_with_staging_streaming(host, bundle, {}, event_callback=display.handle_event)
SSH connection settings (hardcoded for the Docker test container):
SSHHOST = "localhost", SSHPORT = 2222, SSHUSER = "testuser", SSHPASS = "testpass"disablehostkey_checking=True — only appropriate for test containersKey classes and functions:
SSHHost(hostname, port, username, password, disablehostkey_checking) — async context manager for SSH connectionsbuildbundle(modulepath, dependencies=[]) — packages a module for remote execution; returns a bundle with info.content_hash and info.sizestagebundleremote(host, bundle) → remote bundle pathexecuteremotestreaming(host, bundlepath, params, eventcallback) → result with .success, .output, .eventsexecuteremotewithstagingstreaming(host, bundle, params, event_callback) — stages-if-needed then executeshost.runstreaming(command, eventcallback) → (stdout, stderr, rc, events)Module-side event emission (available inside bundles):
emit_progress(percent, message, current=, total=) — progress updatesemit_log(message, level=) — structured log eventsrun_streaming parses JSON lines from stderr as events; plain stdout is captured separately.SSHHost is an async context manager — always use async with host: to ensure connection cleanup.EventProgressDisplay renders Rich progress bars and must be used as a context manager (with display:). For multi-host tracking, call display.makecallback(hostname) to get a per-host callback.stagebundleremote can skip re-upload if the hash matches.AnsibleModule pattern (argumentspec, module.exitjson(changed=True, ...)) but add FTL2 event emission on top.ftl2.ssh: SSHHost — the SSH transport layerftl2.moduleloading.bundle: buildbundle — module packagingftl2.moduleloading.executor: executeremotestreaming, executeremotewithstagingstreaming, stagebundle_remote — remote execution orchestrationftl2.progress: EventProgressDisplay, SimpleEventDisplay — Rich-based progress renderingftl2.events: emitprogress, emitlog — the event protocol that feeds back into the streaming callbacksansible.module_utils.basic: Modules follow Ansible's AnsibleModule interface for argument parsing and result reportingdocker-compose.yml (not shown)