Thoughts on Dynamic Variables

56 views
Skip to first unread message

Cade Lambert

unread,
Aug 30, 2019, 10:50:00 AM8/30/19
to Ansible Project
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?

Dan Linder

unread,
Aug 30, 2019, 4:08:04 PM8/30/19
to Ansible Project
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.

Cade Lambert

unread,
Sep 3, 2019, 9:28:01 AM9/3/19
to Ansible Project
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.

Stefan Hornburg (Racke)

unread,
Sep 3, 2019, 9:48:39 AM9/3/19
to ansible...@googlegroups.com
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 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 <mailto:ansible-proje...@googlegroups.com>.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/ansible-project/38a5d109-d789-465b-9694-470c0b6b59d7%40googlegroups.com
> <https://groups.google.com/d/msgid/ansible-project/38a5d109-d789-465b-9694-470c0b6b59d7%40googlegroups.com?utm_medium=email&utm_source=footer>.


--
Ecommerce and Linux consulting + Perl and web application programming.
Debian and Sympa administration. Provisioning with Ansible.

signature.asc

Karl Auer

unread,
Sep 3, 2019, 10:03:02 AM9/3/19
to ansible-project
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.

--
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.
To view this discussion on the web visit https://groups.google.com/d/msgid/ansible-project/38a5d109-d789-465b-9694-470c0b6b59d7%40googlegroups.com.


--
Karl Auer

Email  : ka...@2pisoftware.com
Website: http://2pisoftware.com


GPG/PGP : 301B 1F4E 624D AD99 242C 7A68 EC24 7113 E854 4A4E
Previous:
958A 2647 6C44 D376 3D63 86A5 FFB2 20BC 0257 5816

Dan Linder

unread,
Sep 3, 2019, 11:58:41 AM9/3/19
to Ansible Project
Dang!  @Karl Auer beat me to this example. :)

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":
---
- hosts: localhost
  gather_facts: false
  vars:
    server_type: standard_server
    userlistsA:
      list1:
        users: 'user1,user2,user3'
      list2:
        users: 'user4,user5,user6'
      list3:
        users: 'user7,user8,user1'

    userlistsB:
      db_server:
        users: 'user1,user2,user3'
      web_server:
        users: 'user4,user5,user6'
      standard_server:
        users: 'user7,user8,user1'

  tasks:
  - name: "Users for db_server - option A"
    set_fact:
      userlist: '{{ userlistsA.list1 }}'
    when: server_type=="db_server"

  - name: "Users for web_server - option A"
    set_fact:
      userlist: '{{ userlistsA["list2"] }}'
    when: server_type=="web_server"

  - name: "Users for standard_server - option A"
    set_fact:
      userlist: '{{ userlistsA.list3 }}'
    when: server_type=="standard_server"

  - debug:
      msg: "Option A - Users setup for {{ server_type }} - {{ userlist }}"

  - name: "Users for {{ server_type }} - option B"
    set_fact:
      userlist: '{{ userlistsB[server_type] }}'

  - debug:
      msg: "Option B - Users setup for {{ server_type }} - {{ userlist }}"


Running this with `ansible-playbook ./dynvar.yml` produces this output:
Output:
 [WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost
does not match 'all'


PLAY [localhost] ******************************************************************************************

TASK [Users for db_server - option A] *********************************************************************
skipping: [localhost]

TASK [Users for web_server - option A] ********************************************************************
skipping: [localhost]

TASK [Users for standard_server - option A] ***************************************************************
ok: [localhost]

TASK [debug] **********************************************************************************************
ok: [localhost] => {
    "msg": "Option A - Users setup for standard_server - {'users': 'user7,user8,user1'}"
}

TASK [Users for standard_server - option B] ***************************************************************
ok: [localhost]

TASK [debug] **********************************************************************************************
ok: [localhost] => {
    "msg": "Option B - Users setup for standard_server - {'users': 'user7,user8,user1'}"
}

PLAY RECAP ************************************************************************************************
localhost                  : ok=4    changed=0    unreachable=0    failed=0    skipped=2    rescued=0    ignored=0   

To unsubscribe from this group and stop receiving emails from it, send an email to ansible...@googlegroups.com.

Cade Lambert

unread,
Sep 3, 2019, 12:14:02 PM9/3/19
to Ansible Project
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.
Reply all
Reply to author
Forward
0 new messages