Ansible-role-nginx-config: Missing defaults for nginx_main_template.*

Created on 7 Sep 2019  ·  15Comments  ·  Source: nginxinc/ansible-role-nginx-config

If you want to change only the NGINX user, while keeping defaults for other vars, you still have to define all the vars under nginx_main_template dict.

With those vars:

nginx_main_template_enable: true
nginx_main_template:
  user: www-data

It causes the following error:

TASK [nginxinc.nginx : (Setup: All NGINX) Dynamically Generate NGINX Main Configuration File] ************************
fatal: [sandbox]: FAILED! => {"changed": false, "msg": "AnsibleUndefinedVariable: 'dict object' has no attribute 'worker_processes'"}

We should be allowed to define only some vars, and keep defaults for the other ones.

bug

Most helpful comment

Or you could use separate dictionaries for default and user configuration and merge them with the combine filter. I've been using a role to deploy airflow where this method is used:
airflow_config: "{{ airflow_defaults_config | combine(airflow_user_config, recursive=True) }}"
I guess this would also remove the need to have hardcoded defaults in the templates?

The role I am referring to can be checked out here.

All 15 comments

Totally agree @alexsegura. The option to define single parameters is on the backlog. Development on the role has been a little bit slower than I'd like lately but things should start to pick up again in the next couple months. That being said, feel free to submit a PR if you wish 😄

Thank you for your message.
Yes, I can contribute a pull request 🙂

The problem I see here and there in this role, is that the defaults are hardcoded.
So if defaults change, you have to remember to change them both in defaults/main.yml, and in templates.

https://github.com/nginxinc/ansible-role-nginx/blob/a92d424bdb5dc51b143c702754bed761e919a576/tasks/conf/upload-config.yml#L8-L14

I suppose it's because when using dicts for defaults, they get replaced. There is a hash_behavior setting but it's global I think.

Do you know a way to retrieve the "untouched" default vars for a role?
Something like role_defaults['var_name']?

@alexsegura I don't know of a great way to accomplish this behaviour. Ideally, you'd want a setup where the role can deploy a useful configuration without using any of the values in defaults/main.yml.

The main thought that pops to mind would be using vars/main.yml to hardcode some of the default values and then do something like | default(var_main_upload_src), but I am not sure that that's the best path forward.

Probably the only way to do it is in the template itself with the default filter.

Right, that is a good solution for template related parameters (and if you look at the template files the default filter is already used in a couple places). And admittedly that would address the original issue. It would be a pretty time consuming task but it's doable.

However, the question remains about what's the best approach for non template related variables, and moreso, is there a best approach?

From what I see here and there, the best approach for defaults is to avoid using dicts, e.g

nginx_main_template_user: www-data

instead of

nginx_main_template:
  user: www-data

That would partially address the issue, and initially that was how the role was structured. But when I started to introduce more complex templating options (e.g. multiple location blocks), dictionaries and lists started to make more sense.

Or you could use separate dictionaries for default and user configuration and merge them with the combine filter. I've been using a role to deploy airflow where this method is used:
airflow_config: "{{ airflow_defaults_config | combine(airflow_user_config, recursive=True) }}"
I guess this would also remove the need to have hardcoded defaults in the templates?

The role I am referring to can be checked out here.

Hm, that is an interesting approach, and I can see it working. Maybe it'd be worth to create a small PoC with one of the smaller dictionaries (I'm thinking of the main or stream templates) to see how good it'd work in practice.

I already tried this for the main template and it was working as expected. However, because I went the path of least effort I merged two dictionaries nginx_default_main_template from defaults and nginx_user_main_template from the users playbook into nginx_main_template.
This would introduce a breaking change so I will refactor the role to use the merged dictionary under a new name and submit a PR.

The http template is much more difficult because there are possibly multiple user dictionaries to merge. Anchors and aliases combined with the merge operator could be an alternative but then the user is responsible to do the merge.
I will spent some time an that front as well.

BTW: Is there a reason why you chose to use a dictionary instead of a list to define multiple http templates? From what I have found the key is never really used.

BTW: Is there a reason why you chose to use a dictionary instead of a list to define multiple http templates? From what I have found the key is never really used.

No, not really. On hindsight I think it may improve readability to have a key for each HTTP template you define, but I am not opposed to changing it to a list if it makes things easier.

I ran into a similar issue and subsequently into this issue. I would like to offer an alternative perspective:

Default values for a configuration should not be hard-coded at all, and be left to the software being installed.

As @alexsegura already pointed out, the problem is that you need to keep the values in sync, which by nature will not always be the case (humans are error-prone).

If you feel like you must provide a default configuration, I would suggest keeping the sub-sections in separate dirs, and combine them at the lowest level if the user specifies a value, and then merge them into the configuration.

But even that, imo, is not within the scope of a role - it should copy the configuration to the target, and not make sure that its values are ok; At most, i would give an error if the software could not start due to configuration error (or use the software's validation function, if available).

Funnily enough, I'm currently working on ways to improve how templating works in the role. It's been a very slow process (I have rather limited bandwidth to dedicate to the role at the moment), but I think I've come up with an OK solution that'd address these issues. Hoping to have the changes live in a separate branch in a couple months max 😉

Any progress with this issue?

Nope. There's still plans to go back to this in the "near" future, but a couple other tasks have taken priority.

Was this page helpful?
0 / 5 - 0 ratings