JW.
JW.

Reputation: 51638

Run Ansible handlers based on changed results in multiple loops

I have an Ansible variable containing a list of web servers (all on the same host):

servers:
  - foo
  - bar
  - baz

And a task that changes their config files, and registers the results in a variable:

- name: create server configs
  template: ...
  with_items: "{{ servers }}"
  notify: restart changed servers
  register: servers_changed

And a handler that restarts only the servers that are changed when that task runs:

- name: restart changed servers
  command: restart-my-server {{ item.item.name }}
  when: item.changed
  with_items: "{{ servers_changed.results }}"

My problem is, I now need multiple tasks like the one above, which change different config files. But if I do that, they'll overwrite the servers_changed variable, so only the last one will be used.

I could register different variables in each tasks, but then I need a different handler for each one. This would get messy. Is there a better way?

Upvotes: 9

Views: 9451

Answers (2)

JW.
JW.

Reputation: 51638

I found an approach that I prefer. This creates a variable restart_servers, containing an array of server names that need to be restarted. After updating a config file, add the changed items to the variable.

vars:

servers:
- name: server1
  port: 1000
- name: server2
  port: 1001

tasks:

- name: create server configs
  template: ...
  with_items: "{{ servers }}"
  notify: restart changed servers
  register: servers_changed

- name: remember which servers need to restart
  set_fact:
    restart_servers: "{{ restart_servers | default([]) + [item.item.name] }}"
  when: item.changed
  with_items: "{{ servers_changed.results }}"

handlers:

- name: restart changed servers
  command: restart-my-server {{ item.name }}
  when: item.name in restart_servers | default([])
  with_items: "{{ servers }}"

The disadvantage is that after each task that might trigger a restart, you need a second task to call set_fact based on the servers that changed.

The advantage is that it's easy to understand, and avoids duplicate handlers or duplicate restarts.

Upvotes: 6

techraf
techraf

Reputation: 68469

Use servers_changed as a composite list and concatenate the results of each task:

- name: create server configs
  template: ...
  with_items: "{{ servers }}"
  notify: restart changed servers
  register: servers_changed_now

- set_fact:
    servers_changed: "{{ servers_changed | default([]) | union(servers_changed_now.results|default([]) }}"

and

- name: restart changed servers
  command: restart-my-server {{ item.item.name }}
  when: item.changed
  with_items: "{{ servers_changed }}"

Upvotes: 5

Related Questions