Node identity, tags, groups & safety actions
This article refers to SDK version v0.5.0. The current SDK version is N/A.
Overview
Before you can target a subset of your fleet, you need a way to describe it. The SDK gives you two independent tools for that: tags, free-form labels on a single node, and groups, named collections of nodes with their own id. Alongside those, client.nodes also covers a node's identity (name, GPS location) and its safety actions, an automatic reaction to disk pressure. All four are the same data you'd otherwise edit from the General Info card on the Node Details page.
Safety Actions. An automatic reaction Barbara Panel can trigger when a node's disk usage crosses a threshold: stopping workloads and/or pruning docker resources on their own, before a human needs to step in.
Learn moreEvery method below takes a node_id: the internal 24-character id field on the Node object returned by client.nodes.list() or client.nodes.resolve(node_name), covered in Getting started. None of the examples that follow re-derive it, assume node = client.nodes.resolve("<barbara-id>") has already run, and use node.id wherever node_id is expected.
Rename a node
client.nodes.update_name(node.id, "floor-2-sensor-01")
update_name(node_id, name) takes a plain string for name and returns None. This is the same value shown as the Node Name column in the Nodes List and editable inline from the page header of Node Details, so pick a name meaningful for search and filtering, since it's what client.nodes.list(search=...) and resolve() both match against.
Renaming a node only changes its display name. It does not change the node's Barbara ID (deviceName), the factory-assigned identifier used by add_node and shown in Get the Barbara ID of the node.
Tag nodes
Tags are per-node labels, useful for quick filtering without setting up a group, the same free-form values you'd type into the Tags field of the General Info card.
client.nodes.add_tag(node.id, "production")
client.nodes.update_tags(node.id, ["production", "floor-2"])
client.nodes.delete_tag(node.id, "production")
add_tag(node_id, tag) appends a single string tag to the node's existing tag list, without touching the others. update_tags(node_id, tags) is different in kind: it takes a full List[str] and replaces the node's entire tag list with it, so pass every tag you want to keep, not just the new one, or the ones you omit are removed. delete_tag(node_id, tag) removes exactly one tag by its string value; there's no numeric tag id to look up first, since a tag is just a string.
To read the current tags back, fetch the node and read its raw payload, since Node doesn't expose a typed tags field:
node = client.nodes.get(node.id)
print(node.raw["tags"])
To go the other way, from a set of tags to the nodes carrying them:
production_nodes = client.nodes.list_by_tags(["production", "floor-2"])
list_by_tags(tags) returns every node carrying at least one of the given tags.
There's no server-side tag filter on the underlying list endpoint (only search/groupIds), so this pages through the whole fleet with paginate() and filters locally on each node's own tags. Fine for selecting a target set of nodes, not meant for a hot path against a very large fleet.
Group nodes
Unlike tags, a group is its own named entity with an id, useful when you want to reference "these five nodes" as a single unit elsewhere in your scripts, the same collections that populate the Group filter on the Nodes List.
group = client.groups.create(
name="floor-2-sensors",
description="All floor 2 nodes",
node_ids=["<node-id-1>", "<node-id-2>"],
)
create(name, description, node_ids, *, user_ids=None) on client.groups takes:
| Parameter | Type | What to pass |
|---|---|---|
name | str | The group's display name, shown in Panel's Group dropdown and filter |
description | str | Free text describing what the group is for |
node_ids | List[str] | The internal id of every node to add, from client.nodes.list()/resolve() |
user_ids | Optional[List[str]] | Barbara Panel user ids to associate with the group, from client.users.list() |
It returns the created Group directly, so you can read group.id immediately without a follow-up get(). update(group_id, name, description, node_ids, *, user_ids=None) takes the same five parameters plus the group_id to update, and, like update_tags, replaces the full membership list, so include every node you want the group to keep, not only the ones you're adding. delete(group_id) removes the group entirely; it does not delete the nodes in it.
group = client.groups.update(
group.id, "floor-2-sensors", "All floor 2 nodes, updated", ["<node-id-1>", "<node-id-2>", "<node-id-3>"],
)
client.groups.delete(group.id)
To see which groups a single node belongs to, call list_groups on client.nodes instead of client.groups:
groups = client.nodes.list_groups(node.id)
list_groups returns a List[Group], since a node can be added to more than one group's node_ids list independently. This is a different question from the single Group dropdown on the General Info card: that field sets a node's primary group, while a node can additionally appear in any number of groups created through client.groups.create().
A group is purely organizational: it doesn't imply a shared deployment target the way a cluster does. See client.groups for the full method list.
Set a node's location
client.nodes.set_location(node.id, lat=40.4168, lng=-3.7038, city="Madrid")
location = client.nodes.get_location(node.id)
set_location(node_id, *, lat, lng, country=None, city=None, region=None) mirrors the map picker behind the + button next to Location on the General Info card: lat and lng are the coordinates as floats, and country, city, region are optional descriptive strings stored alongside them. get_location(node_id) returns a raw dict rather than a typed object, since node location payloads vary in shape depending on how the location was set.
client.nodes.delete_location(node.id)
set_location currently returns a 500 Internal Server Error from the API regardless of the payload sent. Until this is fixed upstream, update a node's location from the General Info card in Panel instead of set_location; get_location and delete_location are unaffected.
Configure automatic safety actions
In the product, a node under sustained disk pressure eventually can't pull new images or write logs, and the operator may not be watching a dashboard at the moment it happens. update_safety_actions reacts to that automatically, the scripted equivalent of Panel's Safety Actions checkboxes: above trigger_threshold, the node can stop its apps and/or prune docker resources on its own. This is a separate, automatic mechanism from the manual Docker Prune actions in Advanced Actions, which an operator triggers by hand rather than a disk-usage threshold.
client.nodes.update_safety_actions(
node.id, trigger_threshold=90, stop_apps=True, prune_volumes=True
)
| Parameter | Type | What it does |
|---|---|---|
trigger_threshold | float | Disk usage percentage that triggers the action, strictly between 0.1 and 99.9 |
stop_apps | bool | Stops every workload on the node, the same effect as clicking Stop on each workload card |
prune_all | bool | Runs every prune operation below in sequence, equivalent to the Prune All checkbox |
prune_images | bool | Removes unused Docker images, equivalent to the Prune Images checkbox |
prune_containers | bool | Removes stopped containers, equivalent to the Prune Containers checkbox |
prune_volumes | bool | Removes volumes not attached to any container, equivalent to the Prune Volumes checkbox |
The SDK always sends all five action flags, defaulting the ones you don't pass to False, and the API requires at least one of them to be True, an empty safety config isn't accepted. trigger_threshold has no default: pass a value every time you call this method, even to update just one of the flags.
prune_volumes and prune_all can delete data. A pruned volume that held application state or logs is gone, the same caveat that applies to the manual Docker Prune Volumes action in Advanced Actions. Set thresholds conservatively on nodes running workloads with volumes you care about.
Summary
You now have the building blocks for organizing a fleet: rename and locate a node, tag it, group it with others, and give it an automatic safety net against disk pressure.
None of this requires touching the Barbara Panel by hand, so it scales to provisioning scripts and fleet-wide maintenance jobs alike.
For the full method list, see client.nodes and client.groups in the Reference. To store credentials and tokens on the same nodes, continue to Node & cluster secrets.