Repository navigation
v0.12.0
Release v0.12.0
Release Notes
Overview
This release introduces a Cluster abstraction layered beneath the existing Fleet concept, giving you a cleaner, more expressive way to organize your host inventory. Where Fleet previously described a flat list of hosts, it is now a list of clusters — named groups of hosts that can be composed into larger fleets. This makes it straightforward to model real-world topologies (e.g., "edge nodes" and "core nodes" as separate clusters, both belonging to a single "homelab" fleet) while pushing to the union of all hosts.
Breaking Changes
Fleet semantics changed — this is the most significant change in the release.
Fleet(name, hosts...)→Fleet(name, clusters...):Fleetnow acceptsClusterRefhandles, notHostRefhandles. A fleet is a named set of clusters, and hosts may overlap across member clusters (they are deduplicated automatically on push).Clusteris the new unit of host grouping: The formerFleetrole (a named set of hosts with a parallelism setting) is nowCluster(name, hosts...). All the host-level options (WithSSHUser,WithSSHPort,WithPrivilege, etc.) and theParallel(n)concurrency control now live onCluster.- Renamed task-scope helpers:
FleetHosts()→ClusterHosts()WithTaskFleet(name)→WithTaskCluster(name)WithFleet(name)(onRegisterMethods) →WithCluster(name)LookupFleet/MustFleetnow resolve toFleetRef(a list of clusters); useLookupCluster/MustClusterfor the host-grouping unit.Fleets()listing now reportsClusters []stringand a flattenedHosts []string.
Migration steps:
- Replace every
Fleet("name", hostA, hostB, ...)call withCluster("name", hostA, hostB, ...). - If you need a group-of-groups, introduce a
Fleet("name", cluster1, cluster2, ...)that references your new clusters. - Rename task-scope calls:
FleetHosts()→ClusterHosts(),WithTaskFleet→WithTaskCluster,WithFleet→WithCluster. - Replace
PushFleet("name", tasks...)withPushCluster("name", tasks...)when pushing to a single host group; usePushFleetwhen pushing across multiple clusters.
If you were using
Fleetpurely as "a set of hosts" with no composition, the rename toClusteris the only change you need — drop the wrapperFleetentirely and push to the cluster directly.
Features
Clusterinventory type — A first-class, named group of hosts with its own parallelism knob (Cluster("edge", h1, h2, h3).Parallel(4)). This is where SSH credentials, privilege mode, and per-host values belong. It gives you a natural place to draw the line between "how to talk to these machines" (cluster) and "which machines are in scope for this recipe" (fleet).Fleetas a list of clusters — A fleet now composes clusters, enabling overlapping host membership. For example, anedgecluster and acorecluster can both include a shared bastion host;PushFleetpushes to each unique host exactly once. This mirrors how infrastructure is actually organized (role-based groups that share some machines).FleetRef.ClusterNames()— Inspect which clusters make up a fleet, useful for debugging and reporting.
Improvements
- Cleaner conceptual separation — Previously "fleet" conflated two ideas: how to connect (SSH user, port, privilege) and which hosts to target. Splitting these into
Cluster(connection + host set) andFleet(composition of clusters) makes recipes easier to read and reuse across environments. - Deduplication on fleet push — Overlapping hosts across clusters are transparently deduplicated, so a shared bastion in two clusters receives exactly one push rather than duplicate or conflicting ones.
- Documentation updated —
helpers.mdandplan.mdnow reference the newCluster/ClusterHosts/WithClusternames, and the gap-analysis doc is corrected to reflectPushCluster.
Bug Fixes
- Test suite corrected for the new API — All fleet tests were renamed and updated (
TestFleetOfClusters,TestClusterDuplicateHostNames,TestPushClusterParallel, etc.) to validate the new cluster/fleet semantics, including a new test confirming that overlapping hosts across clusters are deduplicated correctly.
Summary
If you manage more than a handful of hosts, this release gives you the vocabulary to describe your infrastructure the way you actually think about it: groups of similar machines (clusters) composed into broader scopes (fleets). The cost is a one-time rename, but the payoff is recipes that scale beyond a single flat host list.