Why we use Cfengine: file editing

Here at Normation, we use Cfengine 3 extensively for configuration management across Linux and Windows servers. A question we get often is why Cfengine?

I’d like to focus this post on file editing. Since Configuration Management has a lot to do with configuration files, file editing (either from a template, or just setting parameters) is one of the most common tasks.

Two ways to edit files

Managing configuration often implies setting up the content of configuration files. There are two main approaches to achieve this, each with its assets and drawbacks:

  1. Template based configuration: The easiest and safest way is to use templates, along with variables that hold the desired values. The file to configure is replaced by the result of the application of the values into the template. However, it doesn’t always fit well in an existing and heterogeneous environment, for instance if you want to gradually roll out Configuration Management.
  2. File editing: The most versatile approach is to edit the file, adding or modifying some lines, and removing the unwanted ones. It does fit well in heterogeneous systems, allowing for fine-grain tuning of what is to be managed and configured. However one has to think of all the potential lines of a file: those to be managed, those of no relative importance, and those which are critical.

Code examples

Next we provide examples on how to edit files using each method (specifically, how to edit the /etc/resolv.conf file – a simple but illustrative example).

Please note that the examples are self-contained, but in real world usages you should include the cfengine_stdlib.cf and re-use only the bundles (and the template in the first case) from these examples.

Template based file editing

When you want to set the content of a file based on a template, you need two items:

  • Some string variables, containing the values you want to set: in this example resolvers and searchlist,
  • A template (obviously), with the fully qualified variable names in place of the values to set.

The Cfengine file would be:

And the content of myTemplate.tml is:
[sourcecode language=’text’]
#############################################################
### This file is configured by Cfengine.
### Manually editing the file might lead Cfengine
### to reset its content
#############################################################
search $(set_dns_configuration.searchlist)
nameserver $(set_dns_configuration.resolvers)

[/sourcecode]

The variable names in the template are merely placeholders to be replaced by strings, so you can’t do any repetition, and if the variable doesn’t exist, you’ll end up with variable names in your resulting file (but you would test this in a development environment before going to production anyway, right?).

File edition

When you want to set up the content of a file by editing it, you need at least two things:

  • Variables holding the values (they may be strings or lists of strings (slists)): in this example resolvers and searchlist,
  • Definitions of how to add/set these values: in this example, in the bundle edit_line doresolv. Cfengine uses the power of regular expressions to define which line to edit and where to put it,
  • Optionally, you may define lines you do not wish to have in the files (this is not covered in this example).

The Cfengine file would be:

With this solution, you have much finer control over what is edited:

  • Lines can be repeated using slist rather than string,
  • Other fields can be left untouched (in this second example, the field domain remains as it was, leaving other administrators free to set it as they like).

I need to do something more complex!

Sometimes, the filse to edit are a more complex, with sections delimiting where lines must be.

Let’s imagine we have the following file :

[sourcecode language=’text’]
[section=one]
value1=tokeep
value2=No
value3=don’twant

[section=two]
value2=tokeep
value3=Yes

[/sourcecode]

What we want is to remove value3 from the first section, set value2 in this section to No, and set value3 in the second section to Yes.

This can be achieved with the following Cfengine file (once again, the body part comes from the cfengine_stdlib.cf) :

This example is a bit more complex, so some explanations might be helpful:

  1. The select_region INI_section selects the region where the editing will happen, based on section names in brackets,
  2. For simplication, the lines that are to be replaced are first deleted, then added. Advantages: we are sure that only the right number of lines are present, and the code is a bit more readable. Drawback: the order of the variables in the section is usually not kept.

Conclusions

These examples show only parts of what can be done in terms of file editing with Cfengine, but they give a general idea of the concept. You can also mix and match the different approaches (a section defined by a template, another one changed via editing, and another one left alone, except on servers A and C, for example).

The flexibility and versatility of these solutions allows for gradual rolling out of the configuration management across systems, which is especially important if you have existing systems managed by different teams, and need their voluntary cooperation on implementing configuration management.