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
Written by Michael DeHaan
Related protips
6 Responses
In the 2nd code snippet, shouldn't 'b:' be 'dest:' ?
That's what I too was wondering. :)
Anyway nice tutorial.
Variable references are now {{ item }} instead of ${item} as of 1.2 (i believe)
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.
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
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