Terraform has plan. Kubernetes has --dry-run=server. Ansible has --check. Every mature infrastructure tool grew a way to say “tell me what you’d do, then don’t” — because the alternative is finding out at 2am, two hours into a bringup, that a hostname doesn’t resolve.

vRO workflows don’t come with one. This is the case for adding it to every single one you write, and cascading it through every wrapper.

The shape

Every catalog item in the lab factory has a boolean input, validateOnly, default false. When true the workflow does everything it can without changing anything:

  • authenticate to every endpoint it would touch
  • resolve every name it would use, and fail on the ones that don’t
  • generate every spec it would submit, and run the target’s own validation API on it where one exists (the VCF Installer has one; use it)
  • check for collisions — names, IPs, existing objects
  • report what it would have created, then return CREATE_SUCCESSFUL

The wrapper — the one form that chains hosts, bringup, supervisor, fleet components, identity — has the same checkbox, and cascades it to every component. Tick everything, tick validateOnly, request. Thirty seconds to a few minutes later you have a full-stack plan against the live environment, and nothing has moved.

What it caught

Not hypothetically. On a built environment, the cascaded dry run of the whole stack reported:

  • edge cluster: already exists — correctly recorded, wrapper carried on
  • Ops for Logs: IP_IN_USE on the planned address — right, it’s deployed
  • Ops for Networks: same
  • supervisor: the existing one would be reused; the per-service plan listed which services were already active
  • identity: bind succeeded, group resolved, no changes needed

That’s a plan output. On a fresh environment the same run has caught, at various times: a DNS record missing for one of ~40 required names (the installer’s own pre-flight found it, in seconds, instead of bringup finding it in hour two); a stale content-library image ID; a form field arriving null because a custom form hadn’t finished re-importing — which is a publishing bug the dry run surfaced before anyone requested anything real.

The argument against, answered

“It doubles the code.” It doesn’t — it moves the if (!validateOnly) guard around the mutating call, and the validation logic is code you should have had anyway. What it does force is separating “compute what to do” from “do it”, which is how the workflows should have been structured in the first place.

“Some things can’t be validated without doing them.” True. Say so in the result summary — “would deploy X; no pre-validation available” — rather than skipping the item. Partial plans are still plans.

“We have a test environment.” You have a test environment. A dry run against the target is what catches the collision with the thing that’s already there.

Make it the smoke test

The best consequence: a validateOnly request against a known environment is a regression test for the automation itself, runnable on every change. The factory’s smoke runner does exactly this — request every item with validateOnly: true, assert CREATE_SUCCESSFUL, diff the plan summary against the last run. It takes minutes and it has caught more bugs in the workflows than any amount of code review.

Deploy VCF Stack request form: one checkbox per component, and validateOnly The same form, real or dry-run. One checkbox decides.

Why this matters outside the lab

For anyone who has sat through a failed change window, the value is obvious: a full dry run against the real estate before anything moves. Fewer failed changes, shorter windows, and a plan output that answers the change board’s questions before they’re asked. It also gives auditors something they rarely get from infrastructure automation — evidence of what was going to happen, produced by the same tooling that then did it.

Rules learned

  • Add validateOnly to every workflow. Default false. Wrappers cascade it.
  • Dry-run does everything but mutate: auth, resolve, generate, call the target’s validator, check collisions, report.
  • Where a step truly can’t be pre-validated, say so in the summary. Never skip it silently.
  • A dry run against the real target is a plan. A dry run on every change is a smoke test. Same checkbox.
  • The refactor it forces — compute, then act — is the one you wanted.

Part of The Lab Factory.


Lab environment; opinions my own.