Feature Friday #22: Don't fix, just warn

Posted by Nick Anderson
August 9, 2024

Did you know that CFEngine can simply warn about something not being in the desired state?

Traditionally with CFEngine, you define your desired state and CFEngine works towards making that happen. Sometimes you might not want CFEngine to take action and instead warn that a given promise wants to change something. Let’s take a look at a contrived example.

Say we want the file /tmp/feature-friday-22.txt to exist, we might write a policy that looks like this:

bundle agent __main__
{
  files:
      "/tmp/feature-friday-22.txt"
        create => "true";
}

But, we don’t actually want the file to exist, rather we want a warning. Well, you could implement that using a reports-type promise:

bundle agent __main__
{
  reports:
      "warning: /tmp/feature-friday-22.txt doesn't exist!"
        unless => fileexists("/tmp/feature-friday-22.txt");
}

However, there is a slight difference. A reports promise will be seen as a promise kept - yes it will be in your logs - but it’s a bit less visible in general. Instead, we can attach an action body with the action_policy attribute set to warn. Let’s adjust our first example:

/tmp/feature-friday-22-0.cf
bundle agent __main__
{
  files:
      "/tmp/feature-friday-22.txt"
        create => "true",
        action => warn_dont_fix,
        classes => results( "bundle", "example_warn" );

  reports:
      example_warn_not_kept:: "My promise to ensure /tmp/feature-friday-22.txt was not kept";
}
body action warn_dont_fix
{
    action_policy => "warn";
}

Running the policy we can see that warnings were emitted by the agent and that the files promise itself was not kept. We even get a bit more detail about the described state of the file, like the fact that it would be created with permissions only allowing it to be read by the owner.

command
cf-agent -Kf /tmp/feature-friday-22-0.cf
output
 warning: Should create file '/tmp/feature-friday-22.txt', mode '0600', but only warning promised
 warning: Warnings encountered when actuating files promise '/tmp/feature-friday-22.txt'
R: My promise to ensure /tmp/feature-friday-22.txt was not kept

Let’s take it a bit further, what if we only want to warn when a specific context is true. For example, let’s warn except on the day of the publication date of this post.

Here the action_policy is guarded by a class expression targeting any day except the publication date of this post. Unless it’s the publication date, the policy will just warn, otherwise it will have the default behavior and fix the state.

/tmp/feature-friday-22-1.cf
bundle agent __main__
{
  files:
      "/tmp/feature-friday-22.txt"
        create => "true",
        action => warn_dont_fix_except_publication,
        classes => results( "bundle", "example_warn" );

  reports:
      example_warn_not_kept:: "My promise to ensure /tmp/feature-friday-22.txt was not kept";
      example_warn_repaired:: "My promise to ensure /tmp/feature-friday-22.txt was repaired";
      example_warn_kept:: "My promise to ensure /tmp/feature-friday-22.txt needed no action and was kept";
}
body action warn_dont_fix_except_publication
{
        action_policy => "warn";

    !(Yr2024.August.Day09)::
        action_policy => "fix";
}

Running the policy, on any other day than the publication of the post, causes it to fix the state as desired:

command
cf-agent -Kf /tmp/feature-friday-22-1.cf
output
R: My promise to ensure /tmp/feature-friday-22.txt was repaired

This sort of logic can be tied to maintenance windows or other classes, allowing you to automatically adjust when a promise warns or takes action.

Happy Friday! 🎉