Writing your own validation¶
Validation is the service owner's first job: every consumer request arrives as a PENDING change
instance, and your automation decides whether it may proceed. The collection gives you the two ends
of that job - fetch the queue, write the decision - and leaves the middle to you. This page is that
middle on its own; the
load balancer scenario
shows the same pattern wired into a real BIG-IP deployment.
What "custom validation" is - and isn't¶
NetOrca validates every declaration against the service's JSON Schema at submission time. A
change only becomes PENDING once it has passed, so by the time your playbook sees it the
structure, types, enums and required fields are already guaranteed. Re-checking them in Ansible
just duplicates the platform.
Your custom validation is for the things a schema can't express:
- conflicts with the existing estate (is this VIP / name / subnet already taken?),
- external state - IPAM allocation, CMDB ownership, capacity or quota,
- business rules that depend on who is asking or what else is deployed.
If you have none of these, there is nothing to write: you simply approve every PENDING change.
The shape¶
Poll PENDING, then approve. That is the whole play when there is nothing extra to check:
- name: Validate pending changes
hosts: localhost
gather_facts: false
vars:
# safe by default; -e apply_decisions=true arms the writes
apply_decisions: false
tasks:
- name: Poll the validation queue
netautomate.netorca.netorca_change_instance_info:
state: [PENDING]
exclude_referenced: true
register: pending
# HERE IS YOUR CUSTOM VALIDATION
# Nothing schema-level here - reject the offenders (see below), then:
- name: Approve each pending change
netautomate.netorca.netorca_change_instance:
id: "{{ item.id }}"
state: APPROVED
check_mode: "{{ not (apply_decisions | bool) }}"
loop: "{{ pending.change_instances }}"
loop_control:
label: "#{{ item.id }}"
Rejecting some¶
When you do have a business check, reject the offenders first, then approve the rest - guard the two
tasks with your condition and its negation. reason in the log is shown straight back to the
consumer:
- name: Reject changes that collide with the estate
netautomate.netorca.netorca_change_instance:
id: "{{ item.id }}"
state: REJECTED
log: "rejected: VIP {{ item.new_declaration.declaration.virtual_server.ip }} already in use"
check_mode: "{{ not (apply_decisions | bool) }}"
loop: "{{ pending.change_instances }}"
when: my_conflict_check # <- your test against item
- name: Approve the rest
netautomate.netorca.netorca_change_instance:
id: "{{ item.id }}"
state: APPROVED
check_mode: "{{ not (apply_decisions | bool) }}"
loop: "{{ pending.change_instances }}"
when: not my_conflict_check
Each change carries everything your check needs: item.new_declaration.declaration (the desired
state), item.change_type (CREATE / MODIFY / DELETE), item.service_item, item.commit_id.
Conflict checks are easiest with
declaration search - look the value up
across the estate and reject if it is already claimed.
Both tasks are idempotent and support real check mode, so keep them behind apply_decisions while
you develop: the play reports what it would decide without writing anything.
Approvals are always yours over the API
The service's allow_manual_approval / allow_manual_completion flags govern only GUI (human)
approvals. API transitions like these are always available to the owning team's key; a 403 means
the wrong key or context, not a missing flag. The full lifecycle is in
Check mode and idempotency.
Completing the change¶
The deployment half of the workflow has the same shape and the same marker: poll APPROVED work,
run your infrastructure step - the task marked HERE IS YOUR CUSTOM DEPLOYMENT - then mark the
change COMPLETED with a deployed_item. If the deploy fails, don't touch the change: let the run
fail and leave it APPROVED, and the next scheduled run retries it (the queue is the state). NetOrca
has no "mark this failed" step in the fulfilment loop - never report a failure as COMPLETED, and
never transition a change to ERROR. The deploy examples
show both an imperative and a declarative variant.
Prefer to have the AI review it?
NetOrca Pack can auto-review incoming PENDING changes with a change_instance_validator
processor instead of hand-written checks - see Pack and AI. The two compose:
let the AI clear the obvious cases and keep an Ansible pass for the policies you must guarantee.
Try it¶
- Runnable, service-agnostic:
validate_and_approve.yml. - The same pattern in a real deployment: Stage 1 of the load balancer scenario.