Setting vars conditionally within a *role*

8,978 views
Skip to first unread message

candlerb

unread,
Oct 21, 2013, 9:23:16 AM10/21/13
to ansible...@googlegroups.com
The manual has examples on setting variables conditionally within a *playbook*. e.g.

- hosts: all
  remote_user: root
  vars_files:
    - "vars/common.yml"
    - [ "vars/{{ ansible_os_family }}.yml", "vars/os_defaults.yml" ]
  tasks:
  - name: make sure apache is running
    service: name={{ apache }} state=running

My question is how to do this within a *role*. Specific case:

  action: copy src={{item}} dest=/{{item}} mode=750 group={{snmp_group}}

I want to set snmp_group to "wheel" when ansible_os_family=='RedHat', and "snmp" when ansible_os_family=='Debian'. This logic definitely belongs in the role, not in any playbook which wraps it.

At the moment all I can think of is some Jinja2 conditional buried directly into the assignment:

snmp_group: "{% if ansible_os_family=='RedHat' %}wheel{% else %}snmp{% endif %}"

This seems to work, but it's pretty ugly. I can't see how to do anything equivalent to vars_files in a role, or indeed how to include anything under vars/ except vars/main.yml

What am I missing?

Thanks,

Brian.

John Jarvis

unread,
Oct 21, 2013, 10:29:46 AM10/21/13
to ansible...@googlegroups.com
I think the way I would do this would be to create a var named
"snmp_group" in vars/{{ ansible_os_family}}.yml which would take on
different values for different OS types.
I'm not sure if there is a better way but even if there was I think
that's a better/cleaner way of specifying it rather than adding logic
in your play to set it.
-John
> --
> You received this message because you are subscribed to the Google Groups
> "Ansible Project" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to ansible-proje...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.

Michael DeHaan

unread,
Oct 21, 2013, 9:20:39 PM10/21/13
to ansible...@googlegroups.com
There's not currently a way to set variables conditionally in a role.

What normally happens here is you would use "group_by" to determine which roles, or role variations, to apply.



--
Michael DeHaan <mic...@ansibleworks.com>
CTO, AnsibleWorks, Inc.
http://www.ansibleworks.com/

candlerb

unread,
Oct 22, 2013, 4:43:49 AM10/22/13
to ansible...@googlegroups.com
On Tuesday, 22 October 2013 02:20:39 UTC+1, Michael DeHaan wrote:
There's not currently a way to set variables conditionally in a role.

What normally happens here is you would use "group_by" to determine which roles, or role variations, to apply.


I am trying to avoid duplicating complex tasks when they vary by only one parameter. The following is a real example:

- name: add executables
  action: copy src={{item}} dest=/{{item}} mode=750 group=wheel
  with_items:
    - usr/sbin/snmpd-smartctl-connector
    - usr/sbin/snmpd-mdraid-connector
    - usr/sbin/update-mdraid-cache
    - usr/sbin/update-smartctl-cache
  notify: restart snmpd
  when: ansible_os_family=='RedHat'
- name: add executables
  action: copy src={{item}} dest=/{{item}} mode=750 group=snmp
  with_items:
    - usr/sbin/snmpd-smartctl-connector
    - usr/sbin/snmpd-mdraid-connector
    - usr/sbin/update-mdraid-cache
    - usr/sbin/update-smartctl-cache
  notify: restart snmpd
  when: ansible_os_family=='Debian'

What I want to say is:

- when ansible_os_family=='Debian', set variable snmp_group=snmp
- when ansible_os_family=='RedHat', set variable snmp_group=wheel
- write the task once, with group={{snmp_group}}

It seems there is no good way of doing this in ansible. Options are:

1. Write the tasks multiple times with conditions, as shown above
2. Split into two separate but almost identical roles in separate files. Use groups to select the correct role. That was your suggestion. I think it makes maintaining the logic harder because it's duplicated in different parts of the filesystem, and it puts the onus on the role user to select the correct role.
3. Set up vars from the playbook: this means the role is split into two parts which you must remember to invoke correctly. It's because playbooks have a feature (vars_files) that roles don't.

- hosts: xxx
  vars_files: 
    - roles/snmp/vars/{{ansible_os_family}}.yml
  roles:
    - snmp

4. Use inline jinja2 conditionals in vars/main.yml. This seems like the least bad option here.

[roles/snmp/vars/main.yml]
snmp_group: "{% if ansible_os_family=='RedHat' %}wheel{% else %}snmp{% endif %}"

5. Maybe write a parameterised role, and have two other roles snmp_redhat and snmp_debian which call it via 'meta', passing the correct value for snmp_group? Obscure, and in any case the meta roles can only be executed before the roles within the main role.

C. Morgan Hamill

unread,
Oct 22, 2013, 8:55:22 AM10/22/13
to ansible-project
Excerpts from candlerb's message of 2013-10-22 04:43:49 -0400:
> - when ansible_os_family=='Debian', set variable snmp_group=snmp
> - when ansible_os_family=='RedHat', set variable snmp_group=wheel

You can do something like this:

- set_fact: snmp_group=snmp
when: ansible_os_family == 'Debian'

- set_fact: snmp_group=wheel
when: ansible_os_family == 'RedHat'
--
Morgan Hamill

Luciano Cavalheiro da Silva

unread,
Oct 22, 2013, 9:02:09 AM10/22/13
to ansible...@googlegroups.com, candlerb

I guess the following would work:


- set_fact: snmp_group="wheel"
when: ansible_os_family=='RedHat'

- set_fact: snmp_group="snmp"
when: ansible_os_family=='Debian'

- copy: src={{item}} dest=/{{item}} mode=750 group={{snmp_group}}
with_items:
- usr/sbin/snmpd-smartctl-connector
- usr/sbin/snmpd-mdraid-connector
- usr/sbin/update-mdraid-cache
- usr/sbin/update-smartctl-cache
notify: restart snmpd


[]s
Luciano

candlerb

unread,
Oct 22, 2013, 9:12:47 AM10/22/13
to ansible...@googlegroups.com, candlerb
On Tuesday, 22 October 2013 14:02:09 UTC+1, Luciano Cavalheiro wrote:
I guess the following would work:


It does work, thank you !

I didn't come across the set_fact module before, because:


2. it doesn't have "var" in its name

Regards,

Brian.

Luciano Cavalheiro da Silva

unread,
Oct 22, 2013, 9:20:40 AM10/22/13
to ansible...@googlegroups.com, C. Morgan Hamill
Sorry about the dup!

Michael DeHaan

unread,
Oct 22, 2013, 10:43:09 AM10/22/13
to ansible...@googlegroups.com, C. Morgan Hamill
set_fact is mentioned in the modules documentation.

I agree it's named a bit strangely, but we don't want to change it.

Conditional vars from roles is something we need to think about a bit.


Sorry about the dup!
--
You received this message because you are subscribed to the Google Groups "Ansible Project" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ansible-project+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/groups/opt_out.

Mark Casey

unread,
Oct 22, 2013, 2:49:27 PM10/22/13
to ansible...@googlegroups.com
A question on the use case: Is that example used to add new things to existing hosts, or to initially configure recently created hosts? Also (if this is for new hosts), do you use both OS families or are you future-proofing in case you ever need to do so?

--
Mark

Mark Casey

unread,
Oct 22, 2013, 2:52:14 PM10/22/13
to ansible...@googlegroups.com
Wait are you saying if I created Debian.yml in a role's vars folder and then call that role then all the Debian hosts would import that file? Or, just that I could create Debian.yml and do an 'include:' for vars/{{ ansible_os_family}}.yml manually?

--
Mark

Brian Candler

unread,
Nov 4, 2013, 12:51:58 PM11/4/13
to ansible...@googlegroups.com
I have both Ubuntu and CentOS hosts that I'm managing, and I have a fairly complicated role for configuring snmpd (which includes the mad-hacking MDRAID and SMARTCTL MIBs) that I want to share between them.

This role is generally run when the machine is first installed, but it can be re-run e.g. to push out a modified version of the mad-hacking scripts, new community string etc.


--
You received this message because you are subscribed to a topic in the Google Groups "Ansible Project" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/ansible-project/IknBo5QvJXQ/unsubscribe.
To unsubscribe from this group and all its topics, send an email to ansible-proje...@googlegroups.com.

Michael DeHaan

unread,
Nov 4, 2013, 6:33:56 PM11/4/13
to ansible...@googlegroups.com
This was added already on the 1.4 branch.

Please see this thread.




--
You received this message because you are subscribed to the Google Groups "Ansible Project" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ansible-proje...@googlegroups.com.

For more options, visit https://groups.google.com/groups/opt_out.
Reply all
Reply to author
Forward
0 new messages