Example: deployment dashboard
This article refers to SDK version v0.5.0. The current SDK version is N/A.
Overview
deployment_dashboard.py is a live, fixed-in-place terminal dashboard for monitoring a large fleet against a target deployment state, the screen you'd leave up in an ops room while rolling out, or just watching, a deployment with many nodes and many app versions in the field.
You define a target state once, in a JSON config: which nodes should be online, have an up-to-date Barbara Core, and/or have specific applications deployed at specific versions. The script re-checks every node against it on a timer, redraws in place, never scrolling, and logs an alert the moment a check that was passing starts failing, or recovers.
Get the script
Download deployment_dashboard.py and the sample config deployment_dashboard.sample.json from the SDK's examples/ directory. If you haven't installed the SDK yet, see Getting started.
Set up credentials
The script reads the four Barbara API Credentials from environment variables, or from a .env file placed next to it (loaded automatically, or pointed at with --env-file). See Set up credentials in the Hello World walkthrough for the full picture.
Write the target config
{
"refresh_seconds": 10,
"targets": [
{
"barbara_ids": ["line-3-plc-01", "line-3-plc-02"],
"state": {
"online": true,
"barbara_core_updated": true,
"apps": [{"name": "Alert Manager", "version": "1.2.4"}]
}
}
]
}
Each entry in targets needs at least one selector, barbara_ids, tags, or group, and at least one check under state: online, barbara_core_updated, and/or apps (a list of {"name", "version"} pairs, one per application you expect deployed at an exact version). A node matched by more than one rule gets the union of their checks, with a later rule's online/barbara_core_updated overriding an earlier one for that node, while apps lists accumulate.
Walk through the code
resolve_target_states() resolves every rule's selectors once at startup, not on every refresh cycle:
for barbara_id in rule.get("barbara_ids") or []:
node_ids.append(resolve_node(client, barbara_id).id)
if rule.get("tags"):
node_ids.extend(n.id for n in client.nodes.list_by_tags(rule["tags"]))
if rule.get("group"):
node_ids.extend(resolve_group_node_ids(client, rule["group"]))
A node added to a monitored group or tag afterwards won't be picked up without restarting the script, resolving once keeps the per-cycle cost predictable regardless of how the config's selectors are written.
evaluate_node() is the core of the script, and its docstring makes a specific cost claim worth reading closely: every check for a node comes from a single client.nodes.get() call, since the node document already embeds alive, deviceVersion, and every deployed workload's application name and installed version:
node = client.nodes.get(node_id)
if state.online is not None:
results["online"] = CheckResult(bool(node.raw.get("alive")) == state.online, ...)
if state.barbara_core_updated is not None:
update_available = bool((node.raw.get("deviceVersion") or {}).get("lastVersion", {}).get("updateAvailable"))
results["barbara_core_updated"] = CheckResult(not update_available == state.barbara_core_updated, ...)
Watching more apps, or more checks, on a node this script already monitors adds no extra API calls, only more fields read off the same response.
run_dashboard() is the loop: evaluate every target node, compare each check's result to what it was on the previous cycle, and append an alert line the moment a check flips from passing to failing, or the reverse:
if was_ok is True and not result.ok:
alerts.append(f"[{timestamp}] ALERT {node_name}: {check_name} started failing — {result.detail}")
elif was_ok is False and result.ok:
alerts.append(f"[{timestamp}] RECOVERED {node_name}: {check_name}")
Nothing is logged on the very first cycle, there's no prior state yet to compare against. render() then clears the screen and repaints the whole table plus the last 15 alert lines, using plain ANSI escape codes, no extra dependency, so the dashboard never scrolls out from under you.
Run it
python deployment_dashboard.py deployment_dashboard.sample.json
Stop it with Ctrl+C.
Try it
Start with the sample config against your own fleet, adjusting the Barbara IDs, application name, and version to nodes you actually have. Watch the Alerts panel: nothing appears on the first cycle, only once a check that was passing starts failing, or recovers. Point it at a node you know is offline, or an app deployed at a different version than expected, to see a FAIL row and its reason.
Extend it
- Check running containers, not just the deployed version. Add
client.nodes.workloads.get_running_servicesto confirm an app's containers are actually up, not just that the right version is deployed. - Re-resolve selectors periodically. Refresh
--tags/--groupmembership on an interval instead of only at startup, so a node added to a monitored group later gets picked up without a restart. - Forward alerts elsewhere. Write them to a file, or post to a webhook or alerting system, instead of, or in addition to, the console panel.
Summary
You defined a target deployment state once and watched a live dashboard check a fleet against it continuously, at a fixed API cost per node regardless of how many checks or apps you're watching, with an alert the moment something drifts.
For the full method list behind the checks this script runs, see client.nodes in the Reference.