# Run pre/post tasks once with serial 1

**URL:** <https://forum.ansible.com/t/run-pre-post-tasks-once-with-serial-1/26740>\
**Category:** Ansible Project\
**Created:** [February 14, 2018, 9:28pm UTC](https://forum.ansible.com/t/run-pre-post-tasks-once-with-serial-1/26740 "2018-02-14T21:28:44Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![Michael\_Perzel](https://avatars.discourse-cdn.com/v4/letter/m/8491ac/32.png) [@Michael\_Perzel](https://forum.ansible.com/u/Michael_Perzel)\
**Post date:** [February 14, 2018, 9:28pm UTC](https://forum.ansible.com/t/run-pre-post-tasks-once-with-serial-1/26740/1 "2018-02-14T21:28:44Z")

</div>

I have a playbook where I would like to do a task once before starting a couple roles and once after roles with serial 1. I thought I could accomplish this with pre and post tasks but it looks like they are called once per server.

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/ansible/original/1X/1882d9a01da5d8996a862359b0913cc568a39b84.svg) [@system](https://forum.ansible.com/u/system)\
**Post date:** [February 14, 2018, 10:34pm UTC](https://forum.ansible.com/t/run-pre-post-tasks-once-with-serial-1/26740/2 "2018-02-14T22:34:34Z")

</div>

you want run\_once, not serial

---

<div class="post-metadata">

**Author:** ![Michael\_Perzel](https://avatars.discourse-cdn.com/v4/letter/m/8491ac/32.png) [@Michael\_Perzel](https://forum.ansible.com/u/Michael_Perzel)\
**Post date:** [February 14, 2018, 11:08pm UTC](https://forum.ansible.com/t/run-pre-post-tasks-once-with-serial-1/26740/3 "2018-02-14T23:08:51Z")

</div>

My real use case is a patching playbook. I have a collection of servers I want to patch one at a time (serial: 1) but there are a set of decommision steps I only want to run once for the entire group. Then patch the servers one by one. Then there is a set of commission tasks I want to run once for the entire group. If I put run once on the pre/post tasks. It still gets run once per play eg once per host.

If it helps, the full context is this is a cassandra cluster. I want to stop the repair service, patch the whole cluster 1 node at a time, then start the repair service.

---

<div class="post-metadata">

**Author:** ![Kai\_Stian\_Olstad](https://avatars.discourse-cdn.com/v4/letter/k/e19adc/32.png) [@Kai\_Stian\_Olstad](https://forum.ansible.com/u/Kai_Stian_Olstad)\
**Post date:** [February 15, 2018, 5:49am UTC](https://forum.ansible.com/t/run-pre-post-tasks-once-with-serial-1/26740/4 "2018-02-15T05:49:56Z")

</div>

How to make this work is documented under note section of run\_once.  
[http://docs.ansible.com/ansible/latest/playbooks\_delegation.html#run-once](http://docs.ansible.com/ansible/latest/playbooks_delegation.html#run-once)

---

<div class="post-metadata">

**Author:** ![Michael\_Perzel](https://avatars.discourse-cdn.com/v4/letter/m/8491ac/32.png) [@Michael\_Perzel](https://forum.ansible.com/u/Michael_Perzel)\
**Post date:** [February 15, 2018, 1:12pm UTC](https://forum.ansible.com/t/run-pre-post-tasks-once-with-serial-1/26740/5 "2018-02-15T13:12:38Z")

</div>

Thanks.

when: inventory\_hostname == ansible\_play\_hosts[0]

Is exactly what I need.

---

<div class="post-metadata">

**Author:** ![Michael\_Perzel](https://avatars.discourse-cdn.com/v4/letter/m/8491ac/32.png) [@Michael\_Perzel](https://forum.ansible.com/u/Michael_Perzel)\
**Post date:** [February 15, 2018, 5:25pm UTC](https://forum.ansible.com/t/run-pre-post-tasks-once-with-serial-1/26740/6 "2018-02-15T17:25:40Z")

</div>

In case someone else has this issue, for my post task I that I only want to run on the last host I used the below conditional. Results in skipped tasks but it does accomplish the goal. Not sure if there is a more elegant way to say run on the last host.

when: inventory\_hostname == ansible\_play\_hosts[ansible\_play\_hosts | length - 1]

This results in

TASK [command] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
changed: [mdl-swch01] =\> {“changed”: true, “cmd”: “echo "pre"”, “delta”: “0:00:00.002647”, “end”: “2018-02-15 11:19:37.098522”, “rc”: 0, “start”: “2018-02-15 11:19:37.095875”, “stderr”: “”, “stderr\_lines”: , “stdout”: “pre”, “stdout\_lines”: [“pre”]}

TASK [command] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
changed: [mdl-swch01] =\> {“changed”: true, “cmd”: “echo "task 1"”, “delta”: “0:00:00.003688”, “end”: “2018-02-15 11:19:43.144388”, “rc”: 0, “start”: “2018-02-15 11:19:43.140700”, “stderr”: “”, “stderr\_lines”: , “stdout”: “task 1”, “stdout\_lines”: [“task 1”]}

TASK [command] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
changed: [mdl-swch01] =\> {“changed”: true, “cmd”: “echo "task 2"”, “delta”: “0:00:00.002865”, “end”: “2018-02-15 11:19:49.189866”, “rc”: 0, “start”: “2018-02-15 11:19:49.187001”, “stderr”: “”, “stderr\_lines”: , “stdout”: “task 2”, “stdout\_lines”: [“task 2”]}

TASK [command] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
skipping: [mdl-swch01] =\> {“changed”: false, “skip\_reason”: “Conditional result was False”}

PLAY [Hello World Linux] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*

TASK [command] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
skipping: [mdl-swch02] =\> {“changed”: false, “skip\_reason”: “Conditional result was False”}

TASK [command] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
changed: [mdl-swch02] =\> {“changed”: true, “cmd”: “echo "task 1"”, “delta”: “0:00:00.002640”, “end”: “2018-02-15 11:19:50.853990”, “rc”: 0, “start”: “2018-02-15 11:19:50.851350”, “stderr”: “”, “stderr\_lines”: , “stdout”: “task 1”, “stdout\_lines”: [“task 1”]}

TASK [command] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
changed: [mdl-swch02] =\> {“changed”: true, “cmd”: “echo "task 2"”, “delta”: “0:00:00.002785”, “end”: “2018-02-15 11:19:51.261013”, “rc”: 0, “start”: “2018-02-15 11:19:51.258228”, “stderr”: “”, “stderr\_lines”: , “stdout”: “task 2”, “stdout\_lines”: [“task 2”]}

TASK [command] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
changed: [mdl-swch02] =\> {“changed”: true, “cmd”: “echo "post"”, “delta”: “0:00:00.003841”, “end”: “2018-02-15 11:19:51.683943”, “rc”: 0, “start”: “2018-02-15 11:19:51.680102”, “stderr”: “”, “stderr\_lines”: , “stdout”: “post”, “stdout\_lines”: [“post”]}

---

<div class="post-metadata">

**Author:** ![Michael\_Perzel](https://avatars.discourse-cdn.com/v4/letter/m/8491ac/32.png) [@Michael\_Perzel](https://forum.ansible.com/u/Michael_Perzel)\
**Post date:** [February 15, 2018, 5:51pm UTC](https://forum.ansible.com/t/run-pre-post-tasks-once-with-serial-1/26740/7 "2018-02-15T17:51:22Z")

</div>

Gah not quite there. I use meta\_end play when I calculate that a patch isn’t relevant so that we don’t spend time decomissioning a host that doesn’t need a patch. Problem is this skips the post\_tasks if the last server in the group isn’t relevant. I tried using handlers but that results in 1 execution per node.

I think I might need to re-think my playbook organization and simplify. I could use a workflow in tower to accomplish this simpler without skipped tasks.

---

<div class="post-metadata">

**Author:** ![Kai\_Stian\_Olstad](https://avatars.discourse-cdn.com/v4/letter/k/e19adc/32.png) [@Kai\_Stian\_Olstad](https://forum.ansible.com/u/Kai_Stian_Olstad)\
**Post date:** [February 15, 2018, 6:04pm UTC](https://forum.ansible.com/t/run-pre-post-tasks-once-with-serial-1/26740/8 "2018-02-15T18:04:03Z")

</div>

when: inventory\_hostname == ansible\_play\_hosts | last

---

<div class="post-metadata">

**Author:** ![Kai\_Stian\_Olstad](https://avatars.discourse-cdn.com/v4/letter/k/e19adc/32.png) [@Kai\_Stian\_Olstad](https://forum.ansible.com/u/Kai_Stian_Olstad)\
**Post date:** [February 15, 2018, 6:08pm UTC](https://forum.ansible.com/t/run-pre-post-tasks-once-with-serial-1/26740/9 "2018-02-15T18:08:29Z")

</div>

Maybe 3 plays in a playbook will work for you

- name: Pre  
&nbsp;&nbsp;hosst:

- name: Main  
&nbsp;&nbsp;hosts:  
&nbsp;&nbsp;serial: 1

- name: Post  
&nbsp;&nbsp;hosts:

---

<div class="post-metadata">

**Author:** ![flowerysong1](https://avatars.discourse-cdn.com/v4/letter/f/ecae2f/32.png) [@flowerysong1](https://forum.ansible.com/u/flowerysong1)\
**Post date:** [February 15, 2018, 6:24pm UTC](https://forum.ansible.com/t/run-pre-post-tasks-once-with-serial-1/26740/10 "2018-02-15T18:24:46Z")

</div>

Since you want to run 3 sets of tasks on different sets of servers it would be a lot cleaner to split your playbook into three plays instead of one:

- hosts: patchgroup[0]  
tasks:

- debug: msg=pre

- hosts: patchgroup  
serial: 1  
tasks:

- debug: msg=patch

- hosts: patchgroup[0]  
tasks:

- debug: msg=post

This way you won’t have a bunch of skipped tasks and you can end\_play during patching without affecting your post tasks, since they’re a separate play.

---

<div class="post-metadata">

**Author:** ![Michael\_Perzel](https://avatars.discourse-cdn.com/v4/letter/m/8491ac/32.png) [@Michael\_Perzel](https://forum.ansible.com/u/Michael_Perzel)\
**Post date:** [February 15, 2018, 6:31pm UTC](https://forum.ansible.com/t/run-pre-post-tasks-once-with-serial-1/26740/11 "2018-02-15T18:31:27Z")

</div>

Thanks for the help everyone. That is exactly what I was missing. I forgot you could have different plays in the same playbook. My playbook now looks like:
