Nested vs. Flat variables in roles / collections

I’m looking for guidance, pros, cons, etc. around the topic of using nested vs. flat variables for a collection / roles. The example use case will be for a collection of vmware related roles that do operational tasks like creating vm’s from a template. The collection has multiple roles, eg: (provision_vm, create_template_from_vm, etc). Each role needs auth parameters (ignore the env-vars option, for now). I’m curious if there’s a convention, recommendation or pros / cons for one or the other of these two variable definitions:

vmware_collection_auth:
  host:
  username:
  password:

vs:

vmware_collection_host:
vmware_collection_username:
vmware_collection_password:
1 Like

I personally prefer flat variables, especially for simple types like strings and lists. Dicts are much harder to manipulate and to do overrides of the keys. You have to do merging and similar strategies or manipulate dicts using jinja. Simple types are easily overrideable.

On the other hand, I use dicts effectively for namespacing a bunch of variables that share the same name. For example, if I have a set of some standard variables who’s value depends on the operating system, I would have a dict for each OS and proper values for variables as dict keys. Then I just extract them later depending on the OS.

1 Like

It depends on which method makes things simpler. Flat variables work great for single instance “stuff”. But if you find yourself making more than a couple of variables with otherwise identical names but with “0”, “1”, and “2” on the end, sticking with flat variables may not be doing you any favors.

For example, we have some services where we run multiple instances of an Apache tomcat application on the same host, and that’s spread across multiple hosts, so N instances on each of M hosts = N×M instances. The config for various instances differs by some port numbers and a few other things that can be calculated by jinja expressions.

So we define app_tomcat_first_instance as a heavily nested dict, currently ~60 lines, that serves as a template for all the others. Then we create a list of tomcat configs that our tomcat role can deal with, like this:

app_tomcat_instances:
  - "{{ app_tomcat_first_instance }}" # contains "port_offset: 0"
  - "{{ app_tomcat_first_instance | combine({'port_offset':1}, recursive=true) }}"
  - "{{ app_tomcat_first_instance | combine({'port_offset':2}, recursive=true) }}"
  - "{{ app_tomcat_first_instance | combine({'port_offset':3}, recursive=true) }}"

We used to combine it with a more complicated dict that overrode more values, but clever people got carried away.

Anyway, the point is, rather than passing 60 variables to a role 4 times, our include_role can loop over app_tomcat_instances and pass {{ item }}.

The right answer is, do whatever you’re comfortable maintaining. Good luck.

2 Likes