Hello ansible folk,
I have a custom role called “firewall” that I currently use with CentOS 6. It managed the ip(6)tables rules files and reloads iptables as needed.
Now I have a CentOS 7 server, on which firewalling is done by firewalld, so all my tasks and handlers and everything has to change. I was looking for a way to use the same role to work with both CentOS 6 and 7. I wanted to have:
roles/
firewall/
tasks/
main.yml
CentOS6.yml
CentOS7.yml
And then in main.yml, have something like:
- include: ‘{{ansible_distribution}}{{ansible_distribution_major_version}}.yml’
However, this is not allowed, as I discovered in the documentation.
Is there any way I can keep a single role, and make it work simply with both OS versions?
Regards,
Anand
I approach this with conditional includes
- include: centos6.yml
when: ansible_distribution == "CentOS" and
ansible_distribution_version|int == 6
- include: centos7.yml
when: ansible_distribution == "CentOS" and
ansible_distribution_version|int == 7
The 'int' filter may not actually be required. It might look inelegant but
it's very clear to read. The only issue for me is that ansible-playbook
displays a skipped status for each task it doesn't run for a host instead
of just ignoring them.
Hi Tom,
Thanks for your suggestion. That does work, but as you said, ansible still evaluates and skips all the tasks if the when: condition evaluates to false. With a long task list that results in a lot of unnecessary skips.
I’m hoping the developers have some clever ideas to solve this.
Anand
Anand Buddhdev <arhbkb@gmail.com> napisał:
Hi Tom,
The only issue for me is that ansible-playbook displays a skipped
status
for each task it doesn't run for a host instead of just ignoring
them.
Thanks for your suggestion. That does work, but as you said, ansible
still
evaluates and skips all the tasks if the when: condition evaluates to
false. With a long task list that results in a lot of unnecessary
skips.
I'm hoping the developers have some clever ideas to solve this.
Anand
Another way to do this is to split your role in two, and have separate plays for CentOS 6 and 7. You can still have Ansible detect which host should run which play by grouping them with group_by:
- hosts: all
tasks:
- group_by: key=CentOS_{{ansible_distribution_version}}
- hosts: CentOS_7
roles:
- firewalld
- hosts: all
roles:
- firewall_iptables
Tomasz Kontusz <tomasz.kontusz@gmail.com> napisał:
Anand Buddhdev <arhbkb@gmail.com> napisał:
Hi Tom,
The only issue for me is that ansible-playbook displays a skipped
status
for each task it doesn't run for a host instead of just ignoring
them.
Thanks for your suggestion. That does work, but as you said, ansible
still
evaluates and skips all the tasks if the when: condition evaluates to
false. With a long task list that results in a lot of unnecessary
skips.
I'm hoping the developers have some clever ideas to solve this.
Anand
Another way to do this is to split your role in two, and have separate
plays for CentOS 6 and 7. You can still have Ansible detect which host
should run which play by grouping them with group_by:
- hosts: all
tasks:
- group_by: key=CentOS_{{ansible_distribution_version}}
- hosts: CentOS_7
roles:
- firewalld
- hosts: all
Ugh, hosts: CentOS_6 obviously
Hi Tomasz,
Another way to do this is to split your role in two, and have separate plays for CentOS 6 and 7. You can still have Ansible detect which host should run which play by grouping them with group_by:
Thanks for this. I tried it and it also works. It does mean that every ansible run always shows “changed=1” even if nothing ever changed, because group_by is not idempotent. This bothers the idempotence purist in me
Anand
Anand Buddhdev <arhbkb@gmail.com> napisał:
“Thanks for your suggestion. That does work, but as you said, ansible still evaluates and skips all the tasks if the when: condition evaluates to false. With a long task list that results in a lot of unnecessary skips.”
You can turn off the skipped output in ansible.cfg.
It’s entirely idempotent (which is a confusing word BTW) – it doesn’t make any changes when no changes need to be made.
F(x) = F(F(x))
However, it does return a changed boolean because it doesn’t track when the size of the group changes. there’s a ticket about that.
Attaching a handler to a group_by, however, is very uncommon.
Hey Tomasz,
Thanks for this. I tried it and it also works. It does mean that every
ansible run always shows "changed=1" even if nothing ever changed,
because
group_by is not idempotent. This bothers the idempotence purist in me
Oh, it's as idempotent as you can get. But you are right, it's a pretty useless change notification - you can just put changed_when: no on it
Ok, perfect! This does the trick! I like this approach, and I'm going
to use it to dynamically create a CentOS6 and a CentOS7 group, and
apply roles selectively to them. I'll probably just create separate
"firewall_c7" and "firewall_c6" roles.
Regards,
Anand