Configuration
This reference describes the Barn 0.9.0 release candidate. Barn uses only
the new names and fresh Barn state; it has no compatibility or migration layer
for earlier development builds. Check barn version before scripting against
these contracts. See the release status.
Discovery
Configuration lookup order is explicit -f, then barn.yml,
barn.yaml, pigsty.yml, and pigsty.yaml in the current directory. Every
name uses the same Pigsty-compatible YAML Inventory format.
For plan, up, reload, and recreate, absence of a file falls back to
the applied spec when a deployment exists. validate has no fallback. A
configuration must be a regular non-symlink file no larger than 4 MiB. The first
existing discovery candidate wins; if it is invalid, Barn reports the error
instead of trying the next filename. Renaming a file or moving directories does
not create another deployment; applied state lives in BARN_HOME.
A complete inventory
This creates two managed definitions; the control node is meta. Save it as
barn.yml, then inspect it without starting VMs:
The JSON validation result includes valid, source, spec_hash, and resolved.
In the 0.9 candidate, validate also resolves catalog image references and
accepts --repo; an unreadable catalog adds a warning instead of a false success
claim about images, and local-* image-byte checks remain the responsibility of
up. Validation does not prove host resources, share access, networking, image
bytes, or guest readiness. It never starts VMs or downloads images.
What Barn reads
Barn reads host IPs, nodename, admin_ip, pg_cluster, pg_seq,
node_admin_username, node_admin_uid, and the documented vm_* variables.
admin_ip is read from all.vars; it selects the control node, or the first
managed host is used. All nodes must resolve the same login username. For the
default dba user, an explicit node_admin_uid must be 88. For a custom user,
node_admin_uid is validated as an integer but does not set the guest UID;
Barn does not expose a general UID customization contract.
Everything else is opaque and cannot create drift. This means unconsumed
fields such as pg_role, pg_version, repo_*, and node_packages, not all
possible pg_* or node_* names.
Inside this namespace validation is strict: unknown vm_* names, wrong
types, Jinja expressions, invalid addresses, and conflicting sibling-group
values are errors. Inheritance is all.vars → deeper children.<group>.vars →
host variables. Host values replace an entire list such as vm_disks; lists are
not appended. Different values inherited from groups at the same depth must be
resolved with a host-level override. YAML anchors and merge keys are supported;
explicit keys win, and the first mapping in a merge sequence wins. Duplicate
mapping keys and multiple YAML documents are errors.
Host keys must be IPv4 addresses even for vm_skip: true entries. Skipped hosts
do not consume the 20-node budget or determine the managed subnet, but the
inventory must still contain at least one managed host. Skipping an already
applied node marks it as removed; it does not destroy that VM.
The 0.9 candidate improves errors with the offending rule, value, and line
where available, and suggests a nearby vm_* spelling. Those diagnostics do
not add new inventory variables.
VM variables
| Variable | Default | Meaning |
|---|---|---|
vm_skip |
false |
do not virtualize this real/external host |
vm_image |
u24 |
image family, channel reference, or image@version selector |
vm_version |
unset | newest numeric version matching this prefix, such as 9 or 9.7 |
vm_arch |
native |
deployment-wide Guest architecture: native, amd64, or arm64 |
vm_cpu |
2 |
vCPU count |
vm_mem |
4096 |
MiB integer, or a size such as 8GiB |
vm_disk |
64 |
root disk: GiB integer or an explicit size such as 64GiB |
vm_disks |
[{path: /data}] |
extra disks (one 128 GiB non-persistent disk at /data by default) |
vm_alias |
[] |
guest /etc/hosts, SSH-config, and optional host aliases |
vm_shares |
[] |
QEMU 9p host-directory shares |
An empty host entry is a complete VM. A deployment contains 1–20 managed
hosts; vm_cpu accepts 1–256 and memory must be at least 512 MiB.
Bare integer memory is MiB; bare integer disk sizes are GiB. Explicit size
strings accept positive integers plus B, KiB, MiB, GiB, TiB, KB,
MB, GB, or TB (case-sensitive). 8GiB is valid; 8G, 1.5GiB, and the
quoted unitless string "8192" are not. Root/data disk sizes must be positive;
up also checks the root disk against the selected base image’s virtual size.
Omitting vm_image selects Ubuntu 24.04. To use Debian 13, set
vm_image: d13 under all.vars. Inspect barn plan before applying
changes to an existing Barn inventory.
vm_version keeps short version intent separate from the image family:
An exact Catalog version wins first. Otherwise Barn matches only on a dot
component boundary and selects the numerically newest match: 9.7 resolves to
the newest 9.7.* build, while 9 resolves to the newest 9.x release. Numeric
components are compared as integers, so 9.10 sorts after 9.9. Do not combine
vm_version with a vm_image that already contains :channel or @version.
vm_arch is stricter than ordinary per-host VM fields: when present it must
resolve to one value on every managed host, so define it once in all.vars.
Changing it is a deployment-envelope change and requires whole-deployment
recreation. Linux setup installs only the native emulator; a foreign
architecture also needs its matching qemu-system-* binary and firmware.
Data disks
path is the disk identity and mount point. fs is auto (the default), xfs,
or ext4. A blank auto disk is formatted XFS when the guest has mkfs.xfs
and ext4 otherwise, which matches what the Vagrant flow did. Explicit xfs and
ext4 never fall back. Healthy existing filesystems are reused.
persistent: true keeps the disk across an ordinary destroy; vm_disks: []
means no extra disk. size defaults to 128 GiB for each entry; integer sizes
are GiB and explicit size strings are accepted.
Use clean absolute mount paths such as /data or /data/pg. The derived disk
identity trims leading/trailing / and replaces inner / separators with - and must match [a-z][a-z0-9-]{0,31};
identities and mount paths must be unique within the node. /, system paths
such as /etc, /usr, /root, and /var/lib/barn, and their overlapping
parents/children are refused. Changing a persistent disk’s identity or declaration
can require explicit migration; persistent does not mean every new definition
can automatically reuse the old disk.
Data disks are disposable test storage. up resets unrecognized or confirmed
damaged filesystems to the configured type and reports that old data was
discarded. This includes persistent disks: persistence controls destroy/recreate,
not retention of corrupt contents. Probe errors, missing devices, busy mounts,
and backend I/O failures do not authorize formatting. Root disks and host
shares are outside this recovery path.
Shares
macOS limitation: Barn’s guarded directory
sharing is not supported on macOS; a node with vm_shares cannot start. The
candidate also warns during validate and plan. Omit shares in new macOS labs; full macOS sharing support remains pending.
Changing an existing node’s shares requires recreate, which replaces the root
disk. Preserve needed data before considering that operation. Barn does not
fall back to unchecked host paths.
readonly defaults to true; each node accepts at most eight shares. Host and
guest paths must be clean absolute paths; ~ and relative paths are not expanded.
Host directories must already exist, be caller-owned, have no symlink path
components, and not overlap BARN_HOME. On Linux, prefer the real path (realpath /path/to/source). The
0.9 candidate includes that replacement path in a symlink diagnostic.
Within one node, host sources and guest targets must not overlap. Across nodes,
overlapping host sources are allowed only when all are read-only. Guest targets
must not overlap data-disk mounts, reserved system paths, or the login user’s
.ssh directory. Shares are for trusted development files, not PostgreSQL data. If a requested writable share
cannot support guest writes, Barn tries read-only access and reports the
limitation. Correct permissions and repeat up to retry; Barn does not
recursively change the ownership of host files.
A missing source fails only its node during
up or start. Other selected nodes continue. Restore the original directory or
its host mount and retry that node; Barn never creates an empty replacement.
Restart, reload and recreate validate sources before stopping existing nodes.
Names and addresses
Node name order: nodename, then <pg_cluster>-<pg_seq>, then
node-<last-octet>. Names must be unique, 1–63 lowercase letters/digits/hyphens,
and may not begin or end with -. An explicit non-empty nodename takes
precedence, so unrelated pg_cluster or pg_seq values need not derive a name.
vm_alias is a list of lowercase DNS-style names; aliases must not duplicate a
node name or any other alias in the deployment.
All managed hosts must be in one RFC1918 /24: .1 is the host, .2–.8
are reserved, and nodes use .9–.254.
Inside the guest the fixed-IP interface is the one carrying the inventory
address (ip -br addr); its name is not a Barn contract.
Drift
Barn hashes each resolved node. Added hosts are created by up; selected
existing stopped nodes are started; running peers keep their processes while unfinished guest setup is retried. Changed VM
definitions require per-node recreate; removed hosts are reported but never
destroyed. Deployment architecture, user, or subnet changes require whole-deployment
recreation. Image selectors are resolved to exact image identities by plan/up;
review the plan after a catalog update, even if the inventory text is unchanged.
Changing a field used to derive a node name appears as a missing
old node plus a new node, so prefer stable explicit nodename values.