uaeeug
Last Updated: February 25, 2016
·
30.83K
· mpdehaan
3c1b7e921632632e11d5d2ee59403f5f

Use 'with_items' with complex arguments to simplify handler logic

In Ansible, you may need to perform multiple actions that notify a common handler. An example of this might be is if you are laying down multiple configuration files for an application and need to restart a service if any of those files change.

Ordinarily you would do this in your 'tasks' section:

 - name: template the first thing and restart on change
   template: src=templates/foo.j2 dest=/etc/splat/foo.conf
   notify: 
      - restart fooserv

- name: template the second thing and restart on change
  template: src=templates/bar.j2 dest=/etc/splat/bar.conf
  notify: 
     - restart fooserv

- # etc for all the things you need to template

This can be simplified by using "with_items" and a single notify statement. If any of the tasks change, the service will be notified in exactly the same way that it needs to restart at the end of the playbook run.

- name:  template everything for fooserv
  template: src=${item.src} dest=${item.dest}
  with_items:
     - { src: 'templates/foo.j2', b: '/etc/splat/foo.conf' }
     - { src: 'templates/bar.j2', b: '/etc/splat/bar.conf' }
  notify: 
     - restart fooserv

Note that since we have tasks that take more than one unique argument, we don't just say "$item" in the 'template:' line, but use with_items with a hash (dictionary) variable. You can also keep it a little shorter by using lists, if you like. This is a stylistic preference:

- name:  template everything for fooserv
  template: src=${item.0} dest=${item.1}
  with_items:
     - [ 'templates/foo.j2', '/etc/splat/foo.conf' ]
     - [ 'templates/bar.j2', '/etc/splat/bar.conf' ]
  notify: 
     - restart fooserv

Of course we could also define the list you were walking over in another file, like a "groupvars/webservers" file to define all the variables needed for the webservers group, or a YAML file loaded from the "varsfiles" directive inside the playbook. Look how this can clean up if we do.

- name: template everything for fooserv
  template: src=${item.src} dest=${item.dest}
  with_items: ${fooserv_template_files}
  notify: 
      - restart fooserv
Say Thanks
Respond

6 Responses
Add your response

7167
E4aa6bb8ed486a41d5ec28c844968410

In the 2nd code snippet, shouldn't 'b:' be 'dest:' ?

over 1 year ago ·
7596

That's what I too was wondering. :)
Anyway nice tutorial.

over 1 year ago ·
10720
Bc969b0ad080c2bf131d1474141a1942

Variable references are now {{ item }} instead of ${item} as of 1.2 (i believe)

over 1 year ago ·
11264
3c1b7e921632632e11d5d2ee59403f5f

Also the second form will result in one big list.

This is because you usually want:

- yum: name={{ item }} state=installed
  with_items:
     - alist
     - blist

As such, use the hash form if you want to pass multiple things, the item.0 and item.1 approach is not going to work as above.

over 1 year ago ·
17253
None

Maybe with a jinja2 filter like regex (I don't know if it is available till) or remove suffix could fix the issue to template in mass

over 1 year ago ·
20103
None

yes, I was managed to copy files with regex (ansible 1.8.2):

- name: deploy configs
  template: src={{ item }} dest=/var/{{ item | basename }}
  with_fileglob:
  - /path/to/playbooks/configs/roles/rolename/templates/*.xml
over 1 year ago ·
Filed Under