Generate, edit, and deploy F5 BIG-IP sitebuild answer files — the data-only YAML that drives your sitebuild.yml playbook — straight from a discovered virtual server, run non-interactively on the site collector, with dry-run, drift, and git push-back.
Many F5 estates are built and maintained with a sitebuild pattern: a single reusable playbook (sitebuild.yml) that reads a small, data-only answer file describing one virtual server — its pool, members, nodes, profiles, and iRules — and applies it to the BIG-IP. The playbook is the logic; the answer file is the data.
Versus meets that pattern where it already lives. It generates an answer file directly from a discovered virtual server, so the file matches the object on the box field-for-field, edits and versions it in your git repo, and runs sitebuild.yml non-interactively on the collector inside your network — with a dry run by default and an optional commit-and-push of the applied change.
This page covers what an answer file is in Versus, how it is generated and deployed, and how it fits alongside the other F5 automation formats.
An answer file is a flat YAML document with top-level keys that sitebuild.yml consumes as variables. Versus produces exactly the same shape as a hand-authored sitebuild answer file, so a generated file drops straight into your existing playbook with no translation:
---
# Generated by Versus v2 - answer file for sitebuild.yml
# VS: /Prod/app1.example.com_443 Device: bigip-01 2026-08-19T12:00:00Z
f5: bigip-01
partition: Prod
ip_node:
- name: 10.20.0.11
host: 10.20.0.11
description: web01
- name: 10.20.0.12
host: 10.20.0.12
description: web02
pool:
- name: app1_pool
partition: Prod
lb_method: round-robin
monitors: /Common/https
add_poolmembers:
- pool: /Prod/app1_pool
aggregate:
- address: 10.20.0.11
port: 443
- address: 10.20.0.12
port: 443
virtualserver:
- name: app1.example.com_443
partition: Prod
destination: 10.20.0.50
port: 443
description: App1 HTTPS
pool: /Prod/app1_pool
profiles:
- name: /Common/clientssl
context: clientside
irules:
- /Common/redirect_http
ipprotocol: tcp
source: 0.0.0.0/0
enabled: true
state: present
The keys map to F5 objects the way your sitebuild playbook expects them:
| Key | Contents |
|---|---|
f5 | The target device — the discovered VS's device name (or target if unknown). Overridable at run time. |
partition | The BIG-IP partition the objects live in. |
ip_node | One entry per distinct member address (name equals the IP, per F5 convention); the member's own name becomes a description. |
pool | The pool: name, partition, lb_method (defaults to round-robin), and its first monitor as a full /partition/name path. |
add_poolmembers | An aggregate of {address, port} members under the pool's /partition/name reference. |
virtualserver | The VIP itself — destination, port, pool, profiles (with context), irules, snat, ipprotocol, enabled, and state: present. |
Because the file is built from the VS's discovered configuration — the pool, members, and profiles Versus already read off the device — it mirrors the real object rather than a template. The generated header records the source VS, device, and a UTC timestamp.
Answer files come from a virtual server in your inventory. You can retrieve one for any VS through the API:
GET /api/vs-yml/?vs=<virtual_server_id>
If the VS already has a matched file in a git repo, Versus returns that real file (read off the collector for on-prem repos, or from disk for cloud repos). Otherwise it generates a fresh answer file from the discovered config on the fly:
{
"content": "---\n# Generated by Versus v2 ...",
"ansible_file_id": null,
"file_path": null,
"source": "generated",
"gen_format": "sitebuilder"
}
The default gen_format is sitebuilder — the answer-file format above. Pass gen_format=f5_modules to get the alternative instead (see Two output formats).
To persist a generated or edited file into a repo, save it against the VS:
POST /api/ansible-files/save_for_vs/
{ "virtual_server": "<id>", "content": "---\n...", "file_format": "ansible" }
Versus picks the right repo automatically. A collector-managed device's VS files must live in that site's collector repo, so a BIG-IP on site N routes to site N's repo — never to a cloud repo that couldn't run the workflow. If no repo can be inferred and more than one is available, the response comes back with needs_selection: true and the candidate repos so you can choose.
Deployment is a workflow step, f5.sitebuild, that runs the whole lifecycle on the site collector — git, WSL Ansible, and the F5 all live on-prem behind the customer firewall, and Versus never needs an inbound path to any of them (see Platform Architecture). The step drives four stages, each dispatched to the collector:
git.sync).git.write_file), so the file you deploy reflects current inventory.sitebuild.yml non-interactively with extra-vars, which override the playbook's vars_prompt so nothing blocks on a console prompt.The run stage passes the answer file and the F5 credentials as extra-vars:
ansible-playbook sitebuild.yml \
-e answerfile=<path> \
-e f5=<target> \
-e username=<f5-user> -e password=<...> \
[--check]
F5 credentials are pulled from the F5 device in the workflow's device group — they are never stored in the answer file. When no inventory file is supplied, Versus builds one from the device group so the playbook's hosts: '{{ f5 }}' resolves each device name to its management IP.
Pair-aware by design: because sitebuild.yml gates its config tasks on each unit's own failover status (an "Executing only on Active F5 ltm" block), the step targets the whole [f5] group so the run self-applies on the active unit and config-syncs to the standby — regardless of which unit the answer file happened to name.
f5.sitebuild runs in check mode (--check) by default. A dry run reports what would change and never touches the box; the git push-back is skipped entirely on a dry run. Only a real (non-check) run applies changes and, when enabled, commits the answer file back to git. This makes "preview, then apply" the default path rather than an opt-in.
Every matched answer file can be taken through the collector git flow directly:
POST /api/ansible-files/<id>/run_workflow/
{ "workflow_key": "f5.sitebuild", "check_mode": true }
Versus resolves the file's repo, VS, and device group, stages the file from the current VS, and starts the seeded f5-sitebuild-from-file workflow. On a real run it sets push-back so the applied change lands in git; on a dry run it does not. The response returns a run_id you can poll like any other workflow — see Running Workflows via the API.
The same virtual server can be expressed two ways, and Versus generates both:
| Format | gen_format | Shape | Use when |
|---|---|---|---|
| Sitebuild answer file | sitebuilder | Data-only YAML (virtualserver, pool, add_poolmembers, ip_node) consumed by your sitebuild.yml. | You already run a sitebuild playbook and want the data in its native format. |
| Standard f5_modules playbook | f5_modules | A self-contained f5networks.f5_modules playbook — one file, with hosts/vars/tasks that call bigip_pool, bigip_pool_member, and bigip_virtual_server directly. | You want a stand-alone playbook that doesn't depend on a shared sitebuild playbook. |
Versus also generates AS3 declarations (.as3.json / .as3.yaml) for the same VS. Pick whichever matches how your team runs F5; the choice is per file, and the three extensions stay distinct so an answer file, a standard playbook, and an AS3 declaration for one VS never clobber each other.
An answer file is a statement of desired state. When someone changes the BIG-IP out of band — through the GUI, SSH, or the API — the file and the live object diverge. Versus tracks that drift by parsing each matched file's virtualserver block and comparing it field-by-field against the live discovered VS, normalizing equivalent forms (case, any vs 0.0.0.0, boolean spellings) so only real differences surface:
GET /api/vs-drift/?vs=<id>
{
"has_playbook": true,
"file_path": "Prod/app1.example.com_443.yml",
"differences": [
{ "field": "port", "label": "Port", "playbook": "443", "live": "8443" }
],
"in_sync": false
}
Fields compared include destination, port, partition, ipprotocol, enabled, and description. When you accept the drift, Versus rewrites just those lines in the answer file — preserving the rest of the document — and writes it back through the collector, so the file re-adopts what's actually on the box. Each repo pull or re-match refreshes a per-file drift badge in the background.
Matching itself is address-based: Versus links each file to the VS with the same destination:port — the datacenter-unique identity — because the same application name recurs across sites with different addresses, so name alone would cross-match the wrong datacenter.
f5.sitebuild is an ordinary workflow step, so a sitebuild can be a stage in a larger change — with approvals, gating, and back-out — and driven from the UI or the API. See Workflow Builder.f5.sitebuild inside a larger change.