Many of the Ansible roles we write are concerned with installing and managing the configuration of a particular application or package. For example, we have a role that installs PHP and configures particular settings in the php.ini file according to a Jinja2 template.
My preference for specifying these parameters is to gather them under a single dictionary. This seems like a logical organisation and avoids polluting the Ansible variable namespace with a large number of verbose names. For example, for PHP we might have the following in the role defaults:
1 2 3 4 5 6 7 8 |
|
Each of these settings relates to a parameter in php.ini, which is configured in the template php.ini.j2
, e.g.:
1
|
|
The problem with this method comes when the user wants to change one of those settings. Doing this:
1 2 |
|
…will change the setting for expose_php, yes. But it will also remove all
the other defaults, as we’ve now redefined the entire php_param
dictionary.
(Ansible doesn’t offer a way for variables to inherit or collate values from
multiple definitions at different levels transparently, so you can’t append or
override the values of individual keys in a dictionary simply by defining them
higher up.)
The solution is to allow the role user to specify their own settings in a separate dictionary and then use the combine filter to merge this with the defaults:
1 2 3 4 5 6 7 8 9 |
|
Here, values for matching keys in php_custom_param
will overwrite those
in php_param
and any additional keys will be appended to the original
dictionary. Just remember to keep referring to php_param
in the template
and not the custom parameters. (You might want to define php_param
in
the role vars directory instead, so the user can’t redefine it in a
possibly incompatible way.)
This is a useful pattern but in the case of PHP, we could extend it
further in the template. In its current form, adding support for changing
other PHP parameters or adding new ones would involve adding a new default
value to php_param
and editing the template to reference that value for
the appropriate setting. But if the keys in php_param
are assumed to
always be valid PHP settings (and you’re happy to let users alter
arbitrary settings), we might as well use them as-is for the parameter
name too (and loop through all of them in one pass):
1 2 3 |
|
Typically, PHP reads its configuration settings first from /etc/php.ini
and then from all the files in a defined configuration directory such as
/etc/php.d/
(this is how the standard PHP package in Red Hat/CentOS
behaves). Settings can be duplicated within all these files; the last
matching value is used, so settings in the php.d/
files can override
those in the main configuration. This means we can write our settings out
to an override file and leave the installed configuration file untouched:
1 2 3 |
|
(The example here gives the destination configuration file a name that should ensure it is parsed last by PHP so that none of its settings are overridden. You might want to make this a configurable variable, so that users can change its precedence in the parsing order.)
Note that this method works for Red Hat/CentOS platforms but will need some adaptation for Debian-based distributions as those use different configuration directory paths depending on the context (SAPI) in which PHP is called.