Ansible.builtin.pause hosts

On the documentation it shows examples of the pause module being used without a host defined. But when I use no host on my playbook I get

ERROR! the field 'hosts' is required but was not set

When I define the host as localhost it runs in ansible-playbook but when the playbook is triggered with ansible-rulebook it skips the pause and outputs

skipping: no hosts matched

How am I supposed to use pause? Here’s my full playbook:

- name: Shutdown Linux VMs
  ignore_unreachable: true
  hosts: LinuxVMs
  gather_facts: no

  tasks:
  - name: Schedule Shutdown 1s Out
    ansible.builtin.shell: echo "sleep 1; sudo systemctl poweroff" | at now
    ignore_errors: true

- name: Shutdown Windows VMs
  ignore_unreachable: true
  hosts: WindowsVMs
  gather_facts: no

  tasks:
  - name: Schedule Shutdown 1s Out
    ansible.windows.win_shell: shutdown -s -t 1
    ignore_errors: true

- name: Wait for VMs to shutdown
  gather_facts: no
  tasks:
  - name: Sleep 5min
    ansible.builtin.pause:
      minutes: 5

- name: Shutdown ESXi Hosts
  ignore_unreachable: true
  hosts: ESXiHosts
  gather_facts: no

  tasks:
  - name: Poweroff
    ansible.builtin.shell: poweroff
    ignore_errors: true

- name: Wait for Hosts to shutdown
  gather_facts: no
  tasks:
  - name: Sleep 30sec
    ansible.builtin.pause:
      seconds: 30

- name: Shutdown Storage Array
  ignore_unreachable: true
  hosts: Synology
  gather_facts: no

  tasks:
  - name: poweroff
    ansible.builtin.shell: sudo systemctl poweroff
    ignore_errors: true

Hi,

I think that host keyword is required in a play.

You can specify it as “localhost” but you need to remeber to pass it in a limit (implicit localhost is used with limit and you need to specify it)

2 Likes

Hi,

To complete @tanganellilore answer, it’s not about pause module but about play and tasks blocks. The play block your pause task is defined in (named “Wait for Hosts to shutdown”) is lacking hosts key, which is mandatory for a play block.

Now I get that you want to run this task on local machine; you could indeed define localhost as hosts value, though in this case localhost would need to be defined in your inventory (although there are ways to avoid that, but that’s not the point) and connection would still be ssh. Just add connection: local in addition to hosts: localhost to your play and that should do it.

Another way to do it would be to use delegate_to or local_action; see here.

Yes, this is what I meant in a short message (I’m out of House and with smartphone).

In any case, I consider “wrong” put a pause play to wait a vm reboot.

I refer use a wait_for or a ping with retry/until and delay, because it can be “customized” with variable and it will be possible that reboot require lees time than pause.

It’s will be more elegante and safe (you are sure thst host will be reachable)

1 Like

Like this?
image
It still says “skipping: no hosts matched”

Are you using limit in your run?

If yes, you need to add localhost in your limit or add localhost to your inventory (and group) with parameter “ansible_connection: local” (i don’t like this second solution, because you will missing the implicit localhost).

More info about implicit localhost is here:
https://docs.ansible.com/ansible/latest/inventory/implicit_localhost.html

Your last chance is to use hosts: all and add in all tasks under this play with run_once: true.

But repeat, this is not the best solution for your use case, imho.

Yes, just like this.

18:30|ptn@bender:~/TEMP (bg:1)$ ansible-config dump | grep -Ei 'localhost'
LOCALHOST_WARNING(/home/ptn/conf/ansible/ansible.cfg) = False
18:30|ptn@bender:~/TEMP (bg:1)$ ansible -i ~/conf/ansible/inventories/ --list-hosts all | grep -Ei 'localhost|127.0.0.1'
18:30|ptn@bender:~/TEMP (bg:1)$ less ./testpb.yml 
---

- name: Wait for Hosts to shutdown
  gather_facts: no
  connection: local
  hosts: localhost
  tasks:
  - name: Sleep 10sec
    ansible.builtin.pause:
      seconds: 10
18:30|ptn@bender:~/TEMP (bg:1)$ ansible-playbook testpb.yml

PLAY [Wait for Hosts to shutdown] ******************************************************************************************************************************************************************************************************************************************************************************************

TASK [Sleep 10sec] *********************************************************************************************************************************************************************************************************************************************************************************************************
Monday 06 November 2023  18:31:05 +0100 (0:00:00.009)       0:00:00.009 ******* 
Pausing for 10 seconds
(ctrl+C then 'C' = continue early, ctrl+C then 'A' = abort)
ok: [localhost]

PLAY RECAP *****************************************************************************************************************************************************************************************************************************************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

Monday 06 November 2023  18:31:15 +0100 (0:00:10.045)       0:00:10.055 ******* 
=============================================================================== 
Sleep 10sec -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 10.05s

See, no reference to localhost in inventory nor anywhere, and it works.

I’m not sure what could cause this; could you run this specific play alone, with -vvv on the command line or ANSIBLE_DEBUG=1 envvar set ?

Also, I agree with @tanganellilore, pause module is probably not the best for this usecase. I suggest you have a look to wait_for module, as suggested before.

This ^, do not use the pause module. Please use the wait_for.

You can do something like this if you are waiting for Ansible to reconnect

- name: Wait 400 seconds (using wait_for_connection)
  wait_for_connection:
    delay: 0
    timeout: 400

or if its just an application or non host device you can do this->

- name: Wait 400 seconds (using wait_for)
  wait_for:
    host: "{{ ansible_host }}"
    timeout: 400
    port: 22
  vars:
    ansible_connection: local
2 Likes

No, at least I don’t think so.

Maybe I’m not doing it right but I’m still getting skipping: no hosts matched

makerlandmaster@orcastra:/etc/orcastra$ journalctl -u orcastra -e
Nov 07 12:48:30 orcastra ansible-rulebook[18231]: PLAY [Shutdown ESXi Hosts] ******************************************>Nov 07 12:48:30 orcastra ansible-rulebook[18231]:
Nov 07 12:48:30 orcastra ansible-rulebook[18231]: TASK [Poweroff] *****************************************************>Nov 07 12:48:31 orcastra ansible-rulebook[18231]: [WARNING]: No python interpreters found for host tmpevs01.makerland.x>Nov 07 12:48:31 orcastra ansible-rulebook[18231]: ['python3.11', 'python3.10', 'python3.9', 'python3.8', 'python3.7',
Nov 07 12:48:31 orcastra ansible-rulebook[18231]: 'python3.6', 'python3.5', '/usr/bin/python3', '/usr/libexec/platform->Nov 07 12:48:31 orcastra ansible-rulebook[18231]: 'python2.7', '/usr/bin/python', 'python'])
Nov 07 12:48:31 orcastra ansible-rulebook[18231]: changed: [tmpevs01.makerland.xyz]
Nov 07 12:48:31 orcastra ansible-rulebook[18231]:
Nov 07 12:48:31 orcastra ansible-rulebook[18231]: PLAY [Wait for Hosts to shutdown] ***********************************>Nov 07 12:48:31 orcastra ansible-rulebook[18231]: skipping: no hosts matched
Nov 07 12:48:31 orcastra ansible-rulebook[18231]:
Nov 07 12:48:31 orcastra ansible-rulebook[18231]: PLAY [Shutdown Storage Array] ***************************************>Nov 07 12:48:31 orcastra ansible-rulebook[18231]:
Nov 07 12:48:31 orcastra ansible-rulebook[18231]: TASK [poweroff] *****************************************************>Nov 07 12:48:32 orcastra ansible-rulebook[18231]: [WARNING]: sftp transfer mechanism failed on [dsm.makerland.xyz]. Use
Nov 07 12:48:32 orcastra ansible-rulebook[18231]: ANSIBLE_DEBUG=1 to see detailed information
Nov 07 12:48:32 orcastra ansible-rulebook[18231]: [WARNING]: Platform linux on host dsm.makerland.xyz is using the disc>Nov 07 12:48:32 orcastra ansible-rulebook[18231]: Python interpreter at /usr/bin/python3.8, but future installation of >Nov 07 12:48:32 orcastra ansible-rulebook[18231]: Python interpreter could change the meaning of that path. See
Nov 07 12:48:32 orcastra ansible-rulebook[18231]: https://docs.ansible.com/ansible-
Nov 07 12:48:32 orcastra ansible-rulebook[18231]: core/2.15/reference_appendices/interpreter_discovery.html for more in>Nov 07 12:48:32 orcastra ansible-rulebook[18231]: changed: [dsm.makerland.xyz]
Nov 07 12:48:32 orcastra ansible-rulebook[18231]:
Nov 07 12:48:32 orcastra ansible-rulebook[18231]: PLAY RECAP **********************************************************>Nov 07 12:48:32 orcastra ansible-rulebook[18231]: dsm.makerland.xyz          : ok=1    changed=1    unreachable=0    fa>Nov 07 12:48:32 orcastra ansible-rulebook[18231]: federation02.makerad.makerland.xyz : ok=1    changed=1    unreachable>Nov 07 12:48:32 orcastra ansible-rulebook[18231]: obico01.makerland.xyz      : ok=1    changed=1    unreachable=0    fa>Nov 07 12:48:32 orcastra ansible-rulebook[18231]: tmpevs01.makerland.xyz     : ok=1    changed=1    unreachable=0    fa>
makerlandmaster@orcastra:/etc/orcastra$ cat playbook.yml
- name: Shutdown Linux VMs
  ignore_unreachable: true
  hosts: LinuxVMs
  gather_facts: no

  tasks:
  - name: Schedule Shutdown 1s Out
    ansible.builtin.shell: echo "hello" #echo "sleep 1; sudo systemctl poweroff" | at now
    ignore_errors: true

- name: Shutdown Windows VMs
  ignore_unreachable: true
  hosts: WindowsVMs
  gather_facts: no

  tasks:
  - name: Schedule Shutdown 1s Out
    ansible.windows.win_shell: echo "hello" #shutdown -s -t 1
    ignore_errors: true

- name: Wait for VMs to shutdown
  gather_facts: no
  hosts: localhost
  connection: local
  tasks:
  - name: sleep 10sec
    ansible.builtin.pause:
      seconds: 10

- name: Shutdown ESXi Hosts
  ignore_unreachable: true
  hosts: ESXiHosts
  gather_facts: no

  tasks:
  - name: Poweroff
    ansible.builtin.shell: echo "hello" #poweroff
    ignore_errors: true

- name: Wait for Hosts to shutdown
  gather_facts: no
  hosts: localhost
  connection: local
  tasks:
  - name: Sleep 30sec
    ansible.builtin.pause:
      seconds: 30

- name: Shutdown Storage Array
  ignore_unreachable: true
  hosts: Synology
  gather_facts: no

  tasks:
  - name: poweroff
    ansible.builtin.shell: echo "hello" #sudo systemctl poweroff
    ignore_errors: true
makerlandmaster@orcastra:/etc/orcastra$

How would I get the wait_for module to ensure that the VM or host has shut down? Just because it’s no longer reachable doesn’t mean it isn’t actively using the disk. It could still be shutting down but the ssh server is stopped. In the end, I’m not too worried about making sure that everything is shut down before proceeding. Even if the VMs aren’t shut down and the storage array disconnects the hosts without shutting them down, it’s still better than the power getting cut to the storage array, which is what would happen if the playbook got caught on a single component that isn’t shutting down properly and the UPS runs out of power. Would also damage the UPS. In my testing this weekend, the hosts shutdown in about 30 seconds reliably and the storage shuts down in about another 30. That leaves over 10 minutes for the VMs to shut down. I think if they don’t shut down in that time they never will.

It looks like the implicit localhost does not work when using ansible runner/rulebook. I added the localhost entry as detailed here and it worked. Is that normal or could that be a bug?