Changelog¶
All notable changes to this project are documented here. Format follows Keep a Changelog, and this project adheres to Semantic Versioning.
[0.6.0] - 2026-09-03¶
Added¶
client.clusters.resolve(name): look up a cluster by name, symmetric toclient.nodes.resolve().client.applications.default_services(app_version): builds the(compose_config, app_secrets)a fresh Marketplace/Model workload needs from a published app version's template, decoding its base64 defaults — avoids reimplementing this per caller.
Fixed¶
client.clusters.workloads.create_marketplace_workload/create_model_workload(and theirupdate_*counterparts) now raise a clearValueErrorwhendeployment/placement_constraintsreference a service name absent fromcompose_config/app_secrets, instead of silently adding an extra service and letting the API reject the whole request with a length-mismatch400.
[0.5.0] - 2026-08-08¶
First public release.
Added¶
BarbaraClientandAsyncBarbaraClient, with OAuth2 password-grant authentication, automatic token refresh, and a single automatic retry on a401with a fresh token.- Optional
http2=True(requires thebarbara-api-sdk[http2]extra) — mainly useful forAsyncBarbaraClientunderasyncio.gather, multiplexing many concurrent requests over one connection. - Optional
max_retries(default0): retries a connection error or a429/502/503/504response with exponential backoff, honoring a429'sRetry-Afterheader. A retried request whose body streams from an open file is rewound before resending, so a partially-sent multipart upload is never silently truncated. client.settings(ClientSettings): a read-only snapshot of a client's own transport configuration (timeout/http2/max_retries), separate fromclient.config(credentials and URLs).client.nodes: lifecycle (list,paginate,get,resolve,delete,add_node), identity (name, tags, location, safety actions, groups), Global Secrets, Global Config, docker credentials, actions (reboot,poweroff,provision,deprovision,brick), Node Assets, Barbara Core updates, docker maintenance and volumes, and telemetry.list_by_tagsselects every node carrying at least one of a given set of tags — a client-side convenience, since the wire's list endpoint has no server-side tag filter.client.nodes.network: the Networking card — physical interfaces (Ethernet, WiFi, Mobile), VLANs, hostname, VPN, Proxy, Standalone Mode, IPTables, and NTP servers. Every write is checked (best-effort, non-blocking) against the caller's token role before being sent.client.nodes.workloads: Docker, Marketplace, and Model workloads on a single node — create, update, start, stop, delete, logs, container info, running-service detail, command-result history and pending-action state, and each workload type's own configuration surface:- Docker: App Config only.
- Model: Compose Config only (
compose_config:ports/volumesper service). - Marketplace: App Config, Compose Config, and App Secrets (
app_secrets: per-service environment variables, readable back unlike Global Secrets). Partial updates to just Compose Config or just App Secrets preserve whichever side isn't being changed. - A deployed Marketplace app's published URLs are available through
get_urls. client.clusters: lifecycle (list,paginate,get,create,update,delete), node membership (join, leave, pause, drain, set active, update config), Global Secrets, Global Config, docker credentials, and Swarm-managed docker volumes.client.clusters.workloads: the cluster-level equivalent ofclient.nodes.workloads— the same Docker/Marketplace/Model configuration surface deployed across every node in a cluster at once, plus two configuration axes that only apply at cluster scope: Deployment & Replicas (deployment:mode/replicasper service) and Placement Constraints (placement_constraints: tag-based{tag: value}per service, pinning a service to matching nodes).get_urlsand running-service detail are available by reading the cluster's own current state.client.applications: application and application version CRUD, with streamedmultipart/form-datafile uploads (icon, installable artifact) and a per-calltimeout=override for large uploads.client.models: model and model version CRUD, with the same streamed multipart uploads; a version'ssha256/sizeare computed automatically from the artifact.client.configs: the Config Repository — reusable, named configuration documents (typedapplicationorglobal), referenced by id from a node's/cluster's Global Config or a workload's App Config.client.groups: node group CRUD.client.users: read-only user listing and pagination, withUser.roletyped asUserRole(ADMINISTRATOR/SUPERVISOR/EDITOR/VIEWER).client.alerts: alert listing, acknowledgement, and alert events.client.api_version().- Typed exceptions:
BarbaraApiError,BarbaraAuthError,BarbaraNotFoundError,BarbaraPermissionError. - Full sync and async test coverage using
respxHTTP mocking. - Generated API reference documentation site, built from docstrings with
mkdocs+mkdocstringsand published to GitHub Pages. - Every id passed to a resource method (node id, workload id, cluster id, ...) is percent-encoded before being placed in a request path, so a value containing
/,?, or other URL-structural characters can't redirect a call to an unintended endpoint or inject query parameters. - TLS certificate verification is on by default; disabling it (
verify_tls=False/BBR_VERIFY_TLS=false) emits a runtime warning. BarbaraConfigand the internal token object excludeclient_secret,password, and the access token from theirrepr(), so they can't end up in a log line or traceback by accident.- File uploads (application/model icons and artifacts) stream from disk instead of loading the whole file into memory, so a multi-gigabyte artifact doesn't have to fit in the client process's RAM.
- CI and release workflows pin every third-party GitHub Action to a commit SHA and request only the permissions each job needs.
- A dedicated security workflow runs static analysis (
bandit) and a dependency vulnerability scan (pip-audit) on every push, pull request, and release, and gates PyPI publishing on both passing. - Response fields are typed to match what the API actually returns, including cases where the wire value is an object rather than a plain scalar (
Node.status,Alert.severity,AlertEvent.event_type) or a nested reference object rather than a plain id (Alert.node_id,AlertEvent.node_id/alert_id,Group.node_ids). - Every release is gated on a full read+write lifecycle test (nodes, the applications/models catalog, workloads, Barbara Core update scheduling) against a real Barbara environment. A separate daily, read-only check verifies the live API still matches what this SDK's typed models expect, so an incompatible API change is caught early.
Known issues¶
client.nodes.set_locationcurrently returns a500 Internal Server Errorfor any payload. Use the Panel to update a node's location until this is resolved.client.nodes.network.create_ntp_serverdoesn't return the created entry's id, and there is noGET/list endpoint for NTP servers. Read the current list, including each entry's id, fromclient.nodes.get(node_id).raw["deviceConfig"]["ntpServers"]instead.