Ansible: How to run one Task Host by Host?

66,203

Solution 1

You can run a single task in serial (i.e. host-by-host) by adding throttle: 1 to it.

Example:

---

- hosts: all
  tasks:
      - name: wait in parallel
        command: sleep 20
      - name: wait  in serial
        command: sleep 30
        throttle: 1

References:

NB: throttle was introduced in Ansible 2.9

Solution 2

If you don't want any parallelism in performing the steps in your playbook, set the fork level to 1:

ansible-playbook --forks=1 ...

You can also put this in your ansible cfg file:

[defaults]
forks=1

but if you want it on an individual basis, use the command line option above.

EDIT:

serial: 1 does something completely different: that is like running the playbook for each host in turn, waiting for completion of the complete playbook before moving on to the next host. forks=1 means run the first task in a play on one host before running the same task on the next host, so the first task will be run for each host before the next task is touched.

So you want forks=1 for just one play; unfortunately that is not currently possible.

Solution 3

There's a workaround to this problem - one can pass list of hosts (or a group) to with_items, and then use delegate_to with this list. This way task will be executed host by host.

For example:

- name: start and enable rabbitmq (run task host by host)
  service:
    name: "rabbitmq-server"
    state: "started"
    enabled: true
  delegate_to: "{{ item }}"
  with_items: "{{ groups['rabbitmq-cluster'] }}"
  run_once: true

Solution 4

If you are executing it on a single machine , then exclusive locks issue arises for more than one host .So you should execute one by one for all the hosts .For this you need to have --forks=1 being set when calling ansible playbook command. FOr example: ansible-playbook webserver.yml --forks=1 where webserver.yml has app01 and app02 inside your [webserver]

Share:
66,203

Related videos on Youtube

Elrond
Author by

Elrond

Updated on September 18, 2022

Comments

  • Elrond
    Elrond over 1 year

    On the play-level, we have serial: 1 to allow us to run the whole play one host at a time. But I haven't found a simple way to do this on a single task. This is especially relevant, if the task in question doesn't perform proper locking (for whatever reason).

    One obvious answer is to put the task in its own play. But that doesn't help with roles. (Having to put serial: 1 on the play using the role isn't really intuitive.)

  • Elrond
    Elrond over 8 years
    I was not looking to set this on a whole playbook. That's much to non-granular. serial: 1 let's me set it on a play at least. But I only want to set it on a subitem of a play (what ever the correct name of that is. I thought, it was "task", but comment above seems to disagree).
  • wurtel
    wurtel over 8 years
    serial: 1 does something completely different: that is like running the playbook for each host in turn, waiting for completion of the complete playbook before moving on to the next host. forks=1 means run the first task in a play on one host before running the same task on the next host, so the first task will be run for each host before the next task is touched. So you want forks=1 for just one play; unfortunately that is not currently possible.
  • Elrond
    Elrond over 8 years
    Good point! Would you mind adding that to the answer?
  • Elrond
    Elrond over 7 years
    nope: "run_once: true" means to run the task for exactly one host in the list of hosts. I want to run it for each host in the list, but one after the other.
  • Konstantin Suvorov
    Konstantin Suvorov almost 7 years
    You have to provide a list of hosts instead of just on host named inventory_hostname, otherwise the loop makes no sense.
  • Almenon
    Almenon over 4 years
    For those wondering why run_once: true is in there, try taking it out. You will not like what happens. (so many repeated runs aaaahhhh)
  • wurtel
    wurtel over 3 years
    Yes, Ansible 2.9 was released end 2019, well after the question was asked.