A workflow link in AWX is one of three things: on success, on failure, always. Whether the previous job actually did anything does not come into it, and if you want to branch on a fact from the run, the playbook has to publish that fact itself. Ascender adds a fourth kind of link that tests an artifact, and makes every playbook job publish what it changed and what it failed without a line in the playbook.
A link that tests a value
On Condition is the fourth connector, amber in the visualizer, with the condition in its tooltip and an entry of its own in the legend. It carries four properties:
- Trigger: the parent outcome required before the condition is evaluated: success by default, failure, or always.
- Artifact key: the key to look at in the parent's artifacts, its own plus the ones it inherited.
- Operator: equals, or not equals.
- Expected value: read as JSON when it parses, so
true and 3 compare as a boolean and a number, otherwise as text.
A missing key never matches, whichever operator is used. The link fires only when the trigger outcome happened and the condition came out true, and an edge off a failed node counts as an error path only when it will fire.
Artifacts you do not have to write
Every finished playbook job contributes its own keys, computed from the final play recap:
ascender_stats_changed and ascender_stats_failed: true when any host changed, or failed or went unreachable.
ascender_stats_changed_hosts and ascender_stats_non_changed_hosts: sorted host names.
ascender_stats_failed_hosts and ascender_stats_non_failed_hosts: the same for failures.
ascender_stats_hosts_truncated: true when the play had too many hosts and the four lists were left out.
They are ordinary artifacts, so they propagate to descendant nodes as extra variables exactly as set_stats data does, and a downstream playbook can run against the hosts that changed in the node before it. A key your playbook sets through set_stats always wins over the automatic one of the same name. Only playbook jobs produce them: project updates, inventory syncs and ad hoc commands do not.
ASCENDER_AUTO_STATS_ENABLED turns the whole thing off, and ASCENDER_AUTO_STATS_MAX_HOSTS is the point past which the host lists are dropped and only the booleans kept, so artifacts do not grow through a long workflow. Both are settings in the Jobs category, and can be overridden for one job or one workflow with an extra variable of the same name, where a negative value is ignored in favour of the setting.
Aggregation is a merge rather than last writer wins. Across the slices of a sliced job, the nodes of a nested workflow, or several parents converging on one child, the booleans are OR-ed and the host lists unioned, so a host that failed in one slice is still visible after the merge.
Retrying before branching
Nodes also take a max retries count, 0 by default and capped at 100, since nothing waits between attempts. While a node has retries left, a failed job does not send the workflow down the failure paths: the scheduler treats the node as still running, children stay undecided, convergence nodes keep waiting, and the next cycle spawns a fresh attempt. Only when the budget is spent does the node count as failed and its failure paths run, against the last attempt. A relaunched workflow starts every node with a fresh budget.
Each node has its own budget, so one flaky node does not spend its siblings'. The node's job is always the newest attempt, and the superseded ones stay linked to the workflow rather than disappearing. Some failures are never retried, because a retry cannot change the answer: a canceled job was a person, an approval is a person, a template deleted mid run is not coming back, and a job that could not start at all would only hot loop.
What it looks like together
A hardening playbook runs nightly in check mode. Its node gets an On Condition link with ascender_stats_changed equals true to a job that reports the drift, and the ordinary success link on to the rest of the run. Nothing in the playbook publishes anything, and the interesting branch only fires on the nights something moved.
Where the fields are
The link type is in the link modal and in the Add Node wizard in the visualizer, and the condition lives on /api/v2/workflow_job_template_nodes/N/condition_nodes/. ascender export and ascender import round-trip conditional edges together with their conditions, which matters: without that, an exported workflow comes back with the conditional children as unconditional root nodes. docs/workflow.md in the repository is the reference for all three.
All three are @fernandorocagonzalez's, in #561, #562 and #564. The first began as issue #505, a request for a connector that traverses only when the playbook before it changed something, and the automatic artifacts are what made a whole connector type unnecessary to answer it.
There is an open design thread about what else a node should be able to branch on, Exposing more job data to workflow nodes. If you want the job id, the limit or whether the run was in check mode, that is the thread for it.