Application Delivery Controller

F5 Sitebuild Answer Files

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.


What an answer file is

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:

KeyContents
f5The target device — the discovered VS's device name (or target if unknown). Overridable at run time.
partitionThe BIG-IP partition the objects live in.
ip_nodeOne entry per distinct member address (name equals the IP, per F5 convention); the member's own name becomes a description.
poolThe pool: name, partition, lb_method (defaults to round-robin), and its first monitor as a full /partition/name path.
add_poolmembersAn aggregate of {address, port} members under the pool's /partition/name reference.
virtualserverThe 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.


How it is generated

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.


How it is deployed

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:

  1. Pull — refresh the repo checkout (git.sync).
  2. Stage (optional) — regenerate the answer file from a VS and write it into the checkout (git.write_file), so the file you deploy reflects current inventory.
  3. Run — execute sitebuild.yml non-interactively with extra-vars, which override the playbook's vars_prompt so nothing blocks on a console prompt.
  4. Push (optional) — commit and push the answer file back to on-prem git, recording the applied change.

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.

Dry run first

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.

Running it from a file

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.


Two output formats

The same virtual server can be expressed two ways, and Versus generates both:

Formatgen_formatShapeUse when
Sitebuild answer filesitebuilderData-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 playbookf5_modulesA 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.


Keeping files honest — drift

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.


How it fits the platform

  • Collector-managed git. On-prem repos are bound to a site; the checkout, git operations, and Ansible all run on that site's collector. Git credentials are sealed into the collector's local vault and injected on-prem — the token never rides in the repo URL or on each dispatch. See Collector Security and Secret Vault.
  • Discovery-driven. Answer files are generated from the same inventory the rest of Versus reads, so they stay tied to real objects. See F5 BIG-IP Integration.
  • Workflow-native. 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.

Related