
CFEngine version 2.1.17 introduced ExpandVariables in editfiles blocks. This allows macro expansion in configuration files:
The runnable (with CFEngine) example copy-edit-test.cf policy file will help illustrate these steps:
$ chmod +x copy-edit-test.cf
$ cp copy-edit-test.cf /var/tmp/sourcefile
$ ./copy-edit-test.cf
$ cat /var/tmp/finalfile
If different classes need a different base configuration files, store the configuration under a version control repository, and use tags or branches to hold different configurations. This allows development systems to use a new version of a configuration file, and production systems tested configuration.
One example use of templating: set different log verbosity levels between development and production systems. For example, Apache or log4j could write debug logs in development environments, but log less in production. On the other hand, OpenSSH could log more in critical production or ecommerce environments, and less on development systems.
While the builtin strategies statement can set a random class, a script must be run to map even and odd hostnames or Internet addresses to CFEngine classes. The following example shows how to define either the class even_hostname or odd_hostname depending on the hostname of the system.
Use the modulo script to set the mod_hostname variable to 0 or 1 depending on the numbers in the hostname of the system. This assumes hostnames contain numbers: host001, host002, and so forth.
control:
any::
mod_hostname = ( ExecResult(${cf_script_dir}/modulo 2 ${host}) )
The mod_hostname variable now allows definition of an even_hostname or odd_hostname class:
classes:
any::
even_hostname = ( Strcmp(0,${mod_hostname}) )
odd_hostname = ( any -even_hostname )
In subsequent policy, use the classes to apply different configuration between otherwise identical systems. For example, half of the existing systems could log to a different log server in production environments, while development systems use the same loghost.
classes:
realm_dev = ( dev_example_org )
realm_prod = ( any -dev_example_org )
control:
realm_dev::
app_syslog_loghost = ( loghost.dev.example.org )
app_syslog_loglevel = ( debug )
realm_prod::
app_syslog_loglevel = ( info )
realm_prod.even_hostname::
app_syslog_loghost = ( loghost-1.example.org )
realm_prod.odd_hostname::
app_syslog_loghost = ( loghost-2.example.org )