Hi,
I’ve been using Ansible quite a lot for orchestration, and there are a few limitations that I find strange from a design point of view.
I’m not asking for workarounds here. I know about include_tasks, creating multiple plays, add_host, etc.
What I would like to know is whether these are still deliberate design choices in current Ansible, and what the current reasoning is.
I did some research before posting, but most explanations I found are quite old.
1. Why can’t a block be looped?
Something like this is not possible:
- block:
- task A
- task B
loop: "{{ targets }}"
The workaround is to move the tasks into another file and loop over include_tasks.
Brian Coca confirmed that “blocks do not support any type of loop” in this discussion:
But is there a current explanation of why a block should not be a loopable execution unit?
For orchestration, for each target -> execute this group of tasks seems like a natural operation.
2. Why can delegate_to only target one host?
To execute the same task on several delegates, the expected solution is:
delegate_to: "{{ item }}"
loop:
- host1
- host2
Brian Coca gives this solution here:
Delegation - Multiple and Parallel
I understand how to do it, but I don’t really understand the design choice.
Why shouldn’t delegate_to accept a list, group or host pattern?
Using the task’s loop both for data iteration and execution target iteration also becomes awkward when both are needed.
3. Why can’t a task define/change its host scope?
Brian Coca answered this very clearly in:
Change hosts variable when including another playbook
“you don’t, you create a new play that targets those hosts”
I also found Michael DeHaan’s original explanation around the introduction of delegate_to:
So I understand the Ansible model is basically:
Play -> hosts -> tasks
and not:
Task -> hosts
But is this still considered the right abstraction today, especially for dynamic orchestration where the target machines can change several times during a workflow?
Ansible documentation explicitly describes playbooks as providing configuration, deployment and orchestration functions, including orchestration across multiple sets of machines
For orchestration, operations such as:
remove a server from a load balancer
-> perform several maintenance tasks on that server
-> validate it from a monitoring host
-> add it back to the load balancer
-> repeat for the remaining servers
are quite natural.
Ansible can do all of this, but sometimes the YAML structure becomes much more complicated than the actual orchestration logic because of the Play/Task/Block boundaries.
So my main questions are:
- Are these restrictions still deliberate design choices in current
ansible-core? - What is the current architectural reasoning behind them?
- Are they required by the execution/strategy model, or mainly historical limitations?
- Have these choices been reconsidered since those older discussions?
I’m mainly interested in understanding the design rationale, rather than finding another workaround.