Yep, your suggestions there are the kind of things I had in mind with the 
phrase "ugly-ass workaround". :^) (They're task-level, and can't be applied 
to the inclusion of the role in the playbook; they require baking logic 
about the way you manage colors into the role; etc.)

`run_once: true` is effectively the same as adding `when: 
> inventory_hostname == ansible_play_batch.0` to the task .
>

This is a very clear and concise way to put it, and highlights exactly how 
run_once works, and why it doesn't mean "run this task once", but "run this 
task on the first host in the list of hosts in the play, not the first host 
that you're actually running tasks on". It's not a guarantee that a task 
will run once, it's an alias for a common `when` pattern.

I'm juggling too many other things to want to put in a documentation PR 
right now, but if anyone else does, I think this would be useful to 
clarify. In particular, where the docs say

When “run_once” is not used with “delegate_to” it will execute on the first 
> host, as defined by inventory, in the group(s) of hosts targeted by the 
> play - e.g. webservers[0] if the play targeted “hosts: webservers”. 

 

This approach is similar to applying a conditional to a task

 
I think it'd be clearer if this said something about how it *always* 
executes in the context of the first host, as defined by inventory, in the 
group(s) of hosts targeted by the play -- the delegate_to part doesn't 
change that, it just changes which host actually runs the task -- and that 
this isn't just "similar" to applying a conditional to a task, it's 
*identical* to supplying a conditional to a task, and that in particular, 
this condition is logical-AND-ed with any other conditions on the task, 
such that if the task has conditions that cause it to get skipped on the 
first host in inventory, this condition will cause it to get skipped on all 
the other hosts as well.

On Tuesday, March 20, 2018 at 1:13:58 AM UTC-4, flowerysong wrote:
>
> On Monday, March 19, 2018 at 9:42:58 PM UTC-4, Josh Smift wrote:
>>
>> My use case involved roles. I had something like
>>
>> - hosts: web:app:db
>>   roles:
>>     - role: myrole
>>       when: color == "blue"
>>
>> In the role, there was a task that ran on localhost (via delegate_to), 
>> but only once (via run_once) for the whole batch of hosts.
>>
>> Everything worked fine, except that if the first host in inventory 
>> happened not to be blue, the run_once caused the localhost task to be 
>> skipped. The order of the hosts in inventory was completely arbitrary -- 
>> these were EC2 instances at AWS.
>>
>> The eventual workaround was to add the `when` to every single task in the 
>> role *except* the run_once one, which made both the playbook and the role 
>> less readable.
>>
>
> Disregarding the implementation details, `run_once: true` is effectively 
> the same as adding `when: inventory_hostname == ansible_play_batch.0` to 
> the task . As I said before, if that's not what you want you should instead 
> write a conditional that expresses your actual intent.
>
> Here's one approach:
>
> - group_by:
>     key: color_{{ color | default('octarine') }}
>     
> - name: Run on localhost once
>   delegate_to: localhost
>   debug:
>     msg: His pills, his hands, his jeans
>   when: inventory_hostname == groups.color_blue.0
>
> Or you might opt for something like this, which is overly clever and 
> requires a very recent version of Jinja:
>
> - name: Run on localhost once
>   delegate_to: localhost
>   debug:
>     msg: Suddenly I was a lilac sky
>   vars:
>     first_host: "{{ ansible_play_hosts | map('extract', hostvars) | 
> selectattr('color', 'defined') | selectattr('color', 'equalto', 'blue') | 
> first }}"
>   when: inventory_hostname == first_host.inventory_hostname
>
> Or you might restructure the playbook so it only runs the role on blue 
> hosts and doesn't need a separate conditional, and use `run_once` on the 
> task. The best approach depends on personal taste and other decisions made 
> in writing the playbook and setting up your Ansible environment.
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"Ansible Project" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/ansible-project/5442ecce-dd03-46fa-9903-08b4240617d6%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to