Two Wrongs

CFEngine 3: The Unsung Hero

CFEngine 3: The Unsung Hero

I have been doing a lot more system administration for the past month11 For reasons of part-time work., which has given me a better insight into automated configuration management. On the job, I have learned some Ansible and some Puppet. In my spare time, I have seen a lot of people recommend also Chef and SaltStack.

But then … there is CFEngine. Not very many people talk about CFEngine, but the ones that do fall into one of two camps:

  1. I remember having to use CFEngine when I started out with configuration management back in 2003, and I would never use it again. The more recent tools were made specifically to address problems in CFEngine.
  2. I discovered CFEngine two years ago and all of a sudden configuration management does not mean having to fight my tools. You can tell from how well designed it is that the creator spent 10 years just figuring out how it should work.

The moral of the story is this: CFEngine has improved a lot since 2004. It can do a lot of things that the other configuration management tools cannot do. It is also simple and consistent, making it really easy to learn, and there are many reasons I think it should be the default choice when picking a configuration management system for a new environment.

Let’s see how it works!

Simple Configuration

We create a file with our first cfe configuration, as a sort of “hello world” of configuration management. It may look something like this.

body common control {
    any::
        bundlesequence => { "main" };
}

bundle agent main {
  commands:
    any::
      "/bin/echo"
        args => "Hello, World!";
}

The component of cfe that actually does something is called cf-agent, so we’ll run that with our configuration.22 Now, cfe is kind of finicky about relative paths, so it’s safest to always use absolute paths when dealing with cfe. That’s why you see both /bin/echo and $PWD/helloworld.cf.

/usr/sbin/cf-agent -f $PWD/helloworld.cf

The result is not very surprising. We can also say goodbye before we go.

body common control {
    any::
        bundlesequence => { "main" };
}

bundle agent main {
  commands:
    any::
      "/bin/echo"
        args => "Hello, World!";

      "/bin/echo"
        args => "Goodbye!";
}

If we run this policy with again cf-agent, it should print two lines, right?

/usr/sbin/cf-agent -f $PWD/goodbye.cf

But, kqr, what happened? It just said goodbye!

This is one of the reasons cfe is able to perform so well. By remembering the results of the last execution for just a minute or two, cfe can save lots of time by not re-running commands that would otherwise get executed several times in a row, likely with very little change.

If we want to force cf-agent to re-run everything, we can add the -K flag to the command. This will get us both our lines of output again.

/usr/sbin/cf-agent -Kf $PWD/goodbye.cf

Automated Execution

Server Distribution

Why CFEngine?

  • fast
  • secure (few or no exploits)
  • self-healing
  • portable
  • continuous
  • scalable
  • opportunistic/fault tolerant