Are these limitations still deliberate Ansible design choices?

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:

Support “until” for blocks

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:

New delegate_to feature

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:

  1. Are these restrictions still deliberate design choices in current ansible-core?
  2. What is the current architectural reasoning behind them?
  3. Are they required by the execution/strategy model, or mainly historical limitations?
  4. Have these choices been reconsidered since those older discussions?

I’m mainly interested in understanding the design rationale, rather than finding another workaround.

These are very good questions, indeed. I am also interested.

I know these won’t be satisfying, but just trying to give some short answers to the main questions.

  1. Are these restrictions still deliberate design choices in current ansible-core?

yes

  1. What is the current architectural reasoning behind them?

The reasoning has not changed and not likely to w/o first a major revamp of the engine

  1. Are they required by the execution/strategy model, or mainly historical limitations?

yes and yes

  1. Have these choices been reconsidered since those older discussions?

yes, we do revisit long standing questions every so often, but nothing has changed, see #2