Validations
Keep bad data out of AWX — regex patterns, static allowed-value lists, live query-backed lists, and reusable column templates, all shared across automation templates.
Validation catches bad data at the form, not inside the playbook. A misformatted tenant name that would have triggered an Ansible task failure ten minutes into a bulk run becomes a red squiggle at submission time — before AWX ever sees it.
Fabrik has three validation sources (regex, static list, query list) and two reusable libraries on top (regex patterns, column templates). The underlying goal is the same: write the rule once, reuse it everywhere.
The three validation modes
Every column on every schema picks one of four modes:
| Mode | Rule source | Typical use |
|---|---|---|
none | No validation | Notes, free-form descriptions |
regex | A regex pattern (inline or from the library) | Naming conventions, IP addresses, format-sensitive fields |
static_list | A hard-coded list of allowed values | Environments, short enums, anything that doesn't change |
query_list | Values extracted from a saved query, run live against APIC | "Must be an existing tenant," "must not collide with a deployed VRF" |
The mode is set per column in the schema designer. Validation runs on submit: every row, every column, all errors collected and shown inline before the wizard advances.
Required columns
Required is a separate flag, independent of validation_mode. An empty cell on a required column fails immediately, regardless of what the validation rule would otherwise do. Non-required empty cells skip validation entirely — blank is valid when the field isn't mandatory.
Enum columns
For type: select or type: multiselect, the enum_values list acts as a hard gate before anything else runs. The value must be in the list; no validation mode is involved. Combine with required for a "you must pick one of these."
Static lists — the ValidationList library
A ValidationList is a named, shareable set of allowed values. Instead of typing ['prod', 'staging', 'dev'] into every template's environment column, admins create one ValidationList and every column that needs it references it by name.
Validation → Lists manages the library. Each list has:
- Name (unique, required) —
ACI Tenant Names,Standard Environments,Approved BGP AS Numbers. - Values — the allowed-value array.
- Case sensitive — whether
Prodmatchesprod. - Error message / title — what the user sees when their value doesn't match.
- Public — visible to all users vs. creator only.
- Usage count — how many columns reference it.
Invert logic — the conflict check
Most validation asks "is this value in the list?" Sometimes you want the opposite: "fail if this value is already in the list" — the conflict check.
The column-level validation_invert flag flips the logic. Typical use: a Create Tenant form checks that the proposed tenant name is not in the list of already-deployed tenants. The list is the "existing tenants" set; validation_invert=true turns it into a conflict detector.
This works identically for static lists and query lists.
Usage tracking and deletion protection
usage_count is updated atomically when a column attaches or detaches. A list with usage_count > 0 can't be deleted — Fabrik blocks it rather than silently breaking the templates that point at it. Detach from the referencing columns first, then delete.
Query lists — live APIC validation
query_list mode points a column at a saved query (see Query Builder → Saving and sharing). When the user submits, Fabrik:
- Runs the saved query against the selected APIC connection.
- Extracts the first column of results as the allowed-values list.
- Validates the cell against that list.
- Caches the result for 5 minutes, keyed by
(query_id, connection_id).
The payoff: instead of maintaining a static list of "current tenants" by hand, point the column at a query that reads them live. Deploy a new tenant in APIC, and the next form submission sees it immediately (or within 5 minutes, per the cache).
What a good validation query looks like
A validation query should return a single column — either a simple list (["tn-prod", "tn-staging"]) or dicts with one key per row ([{"name": "tn-prod"}, ...]). Multi-column dicts trigger a warning in the logs and Fabrik uses the first column; the user is responsible for ensuring the query shape is right.
The most common validation query is a Class Query on the relevant ACI class with a Select Columns post-processor narrowing the output to one column. For example: query fvTenant, select name only, save as Existing Tenants.
The per-connection cache key
The cache key includes the APIC connection ID intentionally. The same query against two different APICs can return different tenant lists — caching by query alone would let fabric A's names appear as valid values for fabric B. With connection in the key, each fabric's cached list is isolated.
Cache TTL is 5 minutes. For most use cases this is a good balance; if you need stricter freshness, the cache entry for a specific (query, connection) can be invalidated from the Django cache layer, but there's no in-UI button for it.
Graceful cache degradation
If Redis is unreachable, validation logs a warning and runs without the cache — every row re-runs the query. Workable for small batches, slow for big ones. The cache is a performance optimization, not a correctness requirement.
Regex patterns — the RegexPattern library
Regex validation started inline — type the pattern into the column, done. Two problems with that: the same IPv4 regex ends up copy-pasted into fifty columns, and each copy drifts slightly. The RegexPattern library fixes both.
Validation → Regex Patterns manages the library. Each pattern has:
- Name (unique) —
IPv4 Address,VLAN ID (1-4094),ACI Naming Convention. - Pattern — the regex string. Validated at save time; invalid syntax is rejected.
- Category —
network,naming,format,security,custom. - Test strings — sample inputs with expected match / no-match outcomes. Saved alongside the pattern so future editors know what it's supposed to catch.
- Flags —
['i'],['m'], etc. - Error message — custom message shown when a value doesn't match.
Reference vs. inline
A column references a RegexPattern by ID. At validation time, Fabrik looks up the current pattern string — so editing the shared pattern propagates to every template that uses it.
For columns without a reference, the inline validation string on the column is used as a fallback. Both paths land in the same re.match() check; the reference just lets you share the rule.
The visual builder
The pattern editor includes a small visual builder — character classes, anchors, quantifiers — for users who don't write regex daily. Everything it produces is a plain string you can still edit by hand.
Column templates — shared schema fragments
A ColumnTemplate saves a full column definition (name, display name, type, validation, help text, constraints) for reuse. The schema designer has an Insert from Template button that drops the saved column's config into the current schema.
Two scopes:
- User — your personal templates. Visible only to you.
- Company — org-wide shared templates. Admin-managed. Visible to all users.
The default ordering in the picker is -usage_count, name — the column templates you reuse most surface first.
When to save a column as a template
Every time you find yourself typing the same column config for the third time. Tenant Name, VRF Name, BD Name, VLAN ID, Leaf Node ID — these repeat across templates constantly. Save once, drop in next time, and the validation rule stays consistent across every template that uses it.
How validations chain
When the user submits a request, the order is:
- Required check — required + empty → fail, skip rest.
- Enum check —
select/multiselectwithenum_values→ fail if not in list. - Validation mode — whichever of regex / static_list / query_list was configured.
All errors are collected across all rows and all columns before the response comes back — you see every problem in one pass, not one at a time.
Bypass
Templates can opt into allow_validation_bypass. Users with the awx.bypass_validation permission get a Bypass validation checkbox in the wizard; validation still runs and shows warnings but no longer blocks submission. Disabled by default; grant the permission deliberately.
This is for the rare "I know what I'm doing, trust me" case — a break-glass for incident response, not everyday use.
Validation in workflow templates
For workflow templates with multiple schemas, validation runs per-schema. Errors are reported with both row and schema_index so the wizard highlights the exact sheet and cell.
The rules are identical; the only difference is the bookkeeping for which sheet owns which error.
Troubleshooting
Validation issues that come up often:
- "Validation passes but AWX rejects the data." Validation covers the rules you wrote in Fabrik. If AWX or the playbook has extra constraints (name uniqueness within an org, reserved prefixes), add a matching validation on the Fabrik side.
- "A query_list validation is slow." First hit runs the query; subsequent hits inside 5 min use the cache. If every submission feels slow, check Redis — the cache may be silently failing, degrading to no-cache.
- "My regex matches in a tester but not in Fabrik."
re.match()anchors at the start of the string but not the end. Include$explicitly if you mean "exact match." Also, check for stray trailing whitespace — the saved pattern is stripped automatically but your sample string in the tester might not be. - "The allowed-values list is suddenly wrong." If it's a query_list, the underlying saved query may have changed. Run it yourself and inspect the output column.
- "I can't delete a validation list." It's referenced by one or more columns (
usage_count > 0). Detach from the templates first. - "Bypass doesn't appear for me."
allow_validation_bypassis off on the template, or you don't have theawx.bypass_validationpermission. Both are required.
With schemas designed, validation in place, and approvers configured, the next page — Requests — is the user's side of the flow: picking a template, filling the form, and submitting.
Templates
Wrap an AWX job or workflow template in a Fabrik automation template — input schemas, variable mappings, categories, approval workflows, and check-mode defaults.
Requests
The request wizard — picking a template, choosing APIC and AWX credentials, filling out the data grid, running validation, and submitting to AWX.