Thoughts on Dynamic Variables

I wanted to see how you guys go about building dynamic variables. We have some playbooks/roles that require variables to be built based on various things, such as user input or other variables. I usually end up building a long line of ‘if-then-else’ statements, which can be difficult to read and troubleshoot. Is there a better way to go about this? How do you all tackle this?

A lot of our builds have site or subnet specific differences so we use Ansible facts to include specific YML files for either additional variables or branching the execution.

For example, to choose the proper method to install VMware tools on our systems (RHEL 6 vs 7, and internet access or not) we use something like this:

  • name: “Include the appropriate OS steps.”
    include: “{{ role_path }}/tasks/OSsetup-{{ osver }}-{{ vmwaretools_local|bool }}.yml”
Basically the "osver" variable is set earlier based on the OS name ("RedHat" vs "Debian" vs "Ubuntu"), then use the variable "vmwaretools_local" to know if we need to get from a local repo (internally) or from the VMWare.com Internet site.

The problem I come across is I’ll need logic to decide on the content of a variable and that logic will turn into a long string. For example, when determining which users to add to a system, we might have a variable like:

user_list: "{{ ‘user1,user2,user3’ if server_type=db_server else ‘user4,user5,user6’ if server_type=web_server else ‘user7,user8,user1’ if server_type=standard_server }}’

These can get pretty long depending on what we’re trying to do, and fairly hard to read. I could do multi-line variables I guess, but was wondering if there’s a more clever way to handle stuff like this.

The problem I come across is I'll need logic to decide on the content of a variable and that logic will turn into a long
string. For example, when determining which users to add to a system, we might have a variable like:

user_list: "{{ 'user1,user2,user3' if server_type=db_server else 'user4,user5,user6' if server_type=web_server else
'user7,user8,user1' if server_type=standard_server }}'

These can get pretty long depending on what we're trying to do, and fairly hard to read. I could do multi-line variables
I guess, but was wondering if there's a more clever way to handle stuff like this.

That looks like the users should be named in group variables, e.g.:

db_server:
   users:
     - user1
     - user2
     - user3

That's better and more flexible than your conditional approach.

Regards
           Racke

You could use set_fact: stanzas instead, with when: clauses.

  • set_fact:
    user_list: ‘user1, user2, user3’
    when: server_type = ‘db_server’

Even better, use lists rather than strings. You can always turn one into the other, and lists are more flexible:

  • set_fact:
    user_list: [‘user1’, ‘user2’, ‘user3’]
    when: server_type = ‘db_server’

Or something like this:

vars:
db_users: [‘user1’, ‘user2’, ‘user3’]
web_users: [‘user4’, ‘user5’, ‘user6’]
standard_users: ‘user7’, ‘user8’, ‘user9’]

  • set_fact:
    user_list: “{{ db_users }}”
    when: server_type = ‘db_server’

Or this:

vars:
user_groups:
{

‘db_server’: [‘user1’, ‘user2’, ‘user3’],
‘web_server’: [‘user4’, ‘user5’, ‘user6’],
‘standard_server’: [‘user7’, ‘user8’, ‘user9’]
}

  • set_fact:
    user_list: “{{ user_groups[ server_type ] }}”

The syntax is off the top of my head so probably full of errors, but it should give you some ideas.

Regards, K.

Dang! @Karl Auer beat me to this example. :slight_smile:

Depending on your needs and comfort level, here are two examples with sample output.

The first “userlistA” is closer to your original example and has each list with a name that is not consistent with the server_type variable. That leads to the first three “when” clauses to set the userlist variable based on the server_type provided.

The second section using “userlistB” uses the server_type variable to select the correct user list from the dictionary - it’s a single task in the playbook as opposed to three or more for the first method.

Here is my example playbook named “dynvar.yml”:

Awesome, thanks for the responses. This definitely looks like a more logical, thoughtful approach than cramming a bunch of if-else statements into a single line. I’ll take these back and try reworking my vars file. Thanks again.