Run pre/post tasks once with serial 1

110 views
Skip to first unread message

Michael Perzel

unread,
Feb 14, 2018, 4:28:44 PM2/14/18
to Ansible Project
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.

---
- name: Pre Post Task Test
  hosts: "linux"
  gather_facts: false
  any_errors_fatal: true
  serial: 1
  pre_tasks:
  - shell: echo "pre"

  tasks:
  - shell: echo "tasks"

  post_tasks:
  - shell: echo "post"

Results in:
PLAY [Hello World Linux] ****************************************************************************************************************************

TASK [command] **************************************************************************************************************************************
changed: [mdl-swch01] => {"changed": true, "cmd": "echo \"pre\"", "delta": "0:00:00.002576", "end": "2018-02-14 15:27:31.198276", "rc": 0, "start": "2018-02-14 15:27:31.195700", "stderr": "", "stderr_lines": [], "stdout": "pre", "stdout_lines": ["pre"]}

TASK [command] **************************************************************************************************************************************
changed: [mdl-swch01] => {"changed": true, "cmd": "echo \"tasks\"", "delta": "0:00:00.003271", "end": "2018-02-14 15:27:37.240087", "rc": 0, "start": "2018-02-14 15:27:37.236816", "stderr": "", "stderr_lines": [], "stdout": "tasks", "stdout_lines": ["tasks"]}

TASK [command] **************************************************************************************************************************************
changed: [mdl-swch01] => {"changed": true, "cmd": "echo \"post\"", "delta": "0:00:00.002614", "end": "2018-02-14 15:27:43.294444", "rc": 0, "start": "2018-02-14 15:27:43.291830", "stderr": "", "stderr_lines": [], "stdout": "post", "stdout_lines": ["post"]}

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

TASK [command] **************************************************************************************************************************************
changed: [mdl-swch02] => {"changed": true, "cmd": "echo \"pre\"", "delta": "0:00:00.002461", "end": "2018-02-14 15:27:44.875867", "rc": 0, "start": "2018-02-14 15:27:44.873406", "stderr": "", "stderr_lines": [], "stdout": "pre", "stdout_lines": ["pre"]}

TASK [command] **************************************************************************************************************************************
changed: [mdl-swch02] => {"changed": true, "cmd": "echo \"tasks\"", "delta": "0:00:00.002899", "end": "2018-02-14 15:27:45.271244", "rc": 0, "start": "2018-02-14 15:27:45.268345", "stderr": "", "stderr_lines": [], "stdout": "tasks", "stdout_lines": ["tasks"]}

TASK [command] **************************************************************************************************************************************
changed: [mdl-swch02] => {"changed": true, "cmd": "echo \"post\"", "delta": "0:00:00.002650", "end": "2018-02-14 15:27:45.664172", "rc": 0, "start": "2018-02-14 15:27:45.661522", "stderr": "", "stderr_lines": [], "stdout": "post", "stdout_lines": ["post"]}

PLAY RECAP ******************************************************************************************************************************************
mdl-swch01                 : ok=3    changed=3    unreachable=0    failed=0
mdl-swch02                 : ok=3    changed=3    unreachable=0    failed=0


I am looking for something that would do:
pre tasks
tasks for mdl-swch01
tasks for mdl-swch02
post tasks

Any ideas on how to accomplish this?


Brian Coca

unread,
Feb 14, 2018, 5:34:50 PM2/14/18
to Ansible Project
you want run_once, not serial




--
----------
Brian Coca

Michael Perzel

unread,
Feb 14, 2018, 6:08:51 PM2/14/18
to Ansible Project
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.

Kai Stian Olstad

unread,
Feb 15, 2018, 12:50:14 AM2/15/18
to ansible...@googlegroups.com
On 15.02.2018 00:08, Michael Perzel wrote:
> 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.

How to make this work is documented under note section of run_once.
http://docs.ansible.com/ansible/latest/playbooks_delegation.html#run-once

--
Kai Stian Olstad

Michael Perzel

unread,
Feb 15, 2018, 8:12:38 AM2/15/18
to Ansible Project
Thanks.

when: inventory_hostname == ansible_play_hosts[0]

Is exactly what I need.

Michael Perzel

unread,
Feb 15, 2018, 12:25:41 PM2/15/18
to Ansible Project
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"]}

Michael Perzel

unread,
Feb 15, 2018, 12:51:23 PM2/15/18
to Ansible Project
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.

Kai Stian Olstad

unread,
Feb 15, 2018, 1:04:21 PM2/15/18
to ansible...@googlegroups.com
On Thursday, 15 February 2018 18.25.40 CET Michael Perzel wrote:
> 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]

when: inventory_hostname == ansible_play_hosts | last


--
Kai Stian Olstad

Kai Stian Olstad

unread,
Feb 15, 2018, 1:08:45 PM2/15/18
to ansible...@googlegroups.com
On Thursday, 15 February 2018 18.51.22 CET Michael Perzel wrote:
> 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.

Maybe 3 plays in a playbook will work for you


- name: Pre
hosst:

- name: Main
hosts:
serial: 1

- name: Post
hosts:


--
Kai Stian Olstad

flowerysong

unread,
Feb 15, 2018, 1:24:47 PM2/15/18
to Ansible Project
On Thursday, February 15, 2018 at 12:51:23 PM UTC-5, Michael Perzel wrote:
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.

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.

Michael Perzel

unread,
Feb 15, 2018, 1:31:27 PM2/15/18
to Ansible Project
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:

---
- name: Cassandra Stop Repair
  hosts: localhost
  connection: local
  gather_facts: false
  tasks:
  - shell: echo "stop repair" #Really this is an api call

- name: Patching playbook
  hosts: "{{ host_limit }}"
  gather_facts: true 
  any_errors_fatal: "{{ any_errors_fatal | default('true') }}"
  serial: "{{ serial | default('1') }}"
  roles:
    - { role: yumRelevance } #This contains the meta end play if there's nothing to do so we don't decommission, then commission for no reason.
    - { role: cassandraDecommission } 
    - { role: yumPatch }
    - { role: cassandraCommission } 

---
- name: Cassandra Start Repair
  hosts: localhost
  connection: local
  gather_facts: false
  tasks:
  - shell: echo "start repair" #Really this is an api call
Reply all
Reply to author
Forward
0 new messages